Testing a sorted list with Espresso
Espresso is a pretty powerful tool when it comes to writing acceptance tests for Android. Acceptance tests are the ones that make sure your entire feature (or a certain aspect of the feature) is implemented correctly. The advantage of automating acceptance tests is the simplicity of catching regressions, which usually occur during active development or bug fixing. When you have automated tests, it all comes down to just running them to find out if you broke something by a recent change. Awesome!
In this post I’ll show you how to setup Espresso in your Android project, and will write a simple acceptance test, that checks that a list of Premier League teams is sorted alphabetically. Brew yourself a cup of espresso and fasten your seatbelt!
It’s pretty easy to configure Espresso if you’re using Android Studio and Gradle. Just open the build.gradle file inside the app module and add the following dependencies:
By the way, the complete source code for this project is available on GitHub, so feel free to checkout.
Sync your project with Gradle and sip some coffee while Gradle runs the build. One last detail to finalize the setup is to add the following line to build.gradle under defaultConfig closure:
And we’re done! Let’s continue with writing an acceptance test with Espresso.
Writing an acceptance test
You’ll notice the androidTest directory under the src: this is where the Espresso tests usually live. Go ahead and create a class called TeamsActivityTest. Add a couple of annotations to make your class look like that:
We declare that we’ll be using JUnit version 4 to write our tests. The @LargeTest annotation serves as a hint to the test runner regarding what kind of tests our class contains, and is usually used with Espresso tests. Next, we’ll add the following field to the test class:
Until JUnit 4 support was introduced, Android test classes were usually extending the ActivityInstrumentationTestCase2 class. With JUnit 4 it’s enough to add a field of type ActivityTestRule, annotated with @Rule, to describe how the Activity under test should be started. Check the overloaded versions of ActivityTestRule constructor to see which tweaks can be made to the test startup.
With our test class set, let’s proceed straight to implementing our test case:
onView(), withId() and matches() are all static methods inside the framework, so I prefer to use static imports to make the test definitions look clean and concise. Check the sample code on GitHub for the correct imports.
isSortedAlphabetically() though is a custom Hamcrest matcher, that describes the condition that we want to check on our View, namely, that the contents of the android.R.id.list are sorted in alphabetical order. Here’s how we define the matcher:
We know for sure that we’re using a RecyclerView, so we can safely cast the parameter of matchesSafely() and extract the TeamsAdapter to get to the data. We’ll extractNames() from the list of Team objects, and then use Guava’s Ordering class to check that the list is properly sorted. When writing Hamcrest matchers, don’t overlook the describeTo() method, as it can prove very useful when your test fails. In our describeTo() we’ll shortly describe what the matcher is doing and will also print the data that we stored locally: now when our test fails we’ll know exactly how the dataset looked and can draw conclusions on why the condition has failed.
Now you may wonder where do things like Team and TeamAdapter (or even RecyclerView that we haven’t integrated yet) come from. Writing tests that don’t even compile is actually pretty fine with Test Driven Development, that introduces the “red-green-refactor” cycle: write your tests, make them compile and pass, refactor to remove duplication. We’re currently “red”, so let’s work our way to “green” by writing some code.
First, integrate the RecyclerView by adding the following dependency to the app/build.gradle file:
In case you already have a MainActivity in your project, rename it to TeamsActivity, otherwise create it from scratch. TeamsActivity will use the following layout. Team is our POJO and it looks like this:
Notice the BY_NAME_ALPHABETICAL Comparator — that’s the one we’ll use to sort the teams as required.
Next is the TeamsAdapter class, which is pretty straightforward:
The row_team layout can be found here. Now let’s add the code, that will create Team objects and initialize our TeamsAdapter, to TeamsActivity:
We’re using the Team.BY_NAME_ALPHABETICAL here to properly sort our items before passing them to the adapter.
Please fill the gaps in the code by checking the sample on GitHub.
And we’re done! Now you can run the test either by right-clicking the TeamsActivityTest class and selecting the “Run” command, or running the following from the command line:
The test should run fine, but in case they fail — you’ll usually have a pretty helpful output from Espresso to help you debug the issue.
Now, we have an acceptance test written in Espresso, that automatically checks that our feature has been implemented correctly. As already mentioned, the complete sample code for this project is available on GitHub.
Are you writing Espresso tests to validate your features? I’d love to hear from you! Got any feedback, or noticed any errors? Please drop a comment or contact me directly. Cheers!
Originally published at blog.egorand.me on November 21, 2015.