One thing that I notice when I talk to Android developers is that a lot of them don’t put an emphasis on testing. They say that it’s too hard to write them or that they are too hard to integrate and set up, or give a bunch of other reasons why they don’t. But it’s actually pretty simple to write Espresso tests, and they really aren’t that hard to integrate with your code base.
Easy to write
Espresso tests are dead simple to write. They come in three parts.
- ViewMatchers – something to find the view to act upon/assert something about
- ViewActions – something to perform an action (type text, click a button)
- ViewAssertions – something to verify what you expect
For example, the following test would type the name “Steve” into an EditText with the id name_field
, click a Button with the id greet_button
and then verify that the text “Hello Steve!” appears on the screen:
1 2 3 4 5 6 |
|
Seems simple enough right? But what about when other threads are involved?
Integration
From the Espresso documentation:
The centerpiece of Espresso is its ability to seamlessly synchronize all test operations with the application under test. By default, Espresso waits for UI events in the current message queue to process and default AsyncTasks* to complete before it moves on to the next test operation. This should address the majority of application/test synchronization in your application.”
But if you’re like me, you’re not writing AsyncTasks to handle your background operations. My go-to tool for making HTTP requests (probably one of the most common uses of AsyncTask) is Retrofit. So what can we do? Espresso has an API called registerIdlingResource
, which allows you to synchronize your custom logic with Espresso.
With this knowledge, one way you might approach this is to implement a mock version of your Retrofit interface, and then use something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
This tells Espresso that your app is idle after the methods are called. But you should immediately see the problem here – you’ll end up writing a TON of boilerplate. As you have more methods in your interface, and lot of repeated increment and decrement code…there must be a better way. (There is!)
The “trick” lies right in the selling point in the Espresso documentation, “Espresso waits for UI events… and default AsyncTasks to complete”. If we could somehow execute our Retrofit requests on the AsyncTasks’ ThreadPoolExecutor, we’d get sychronization for free!
Fortunately, Retrofit’s RestAdapter.Builder
class has just such a method!
1 2 3 |
|
And it’s that simple – Now you have no excuse not to write some Espresso tests!
More Resources
Thanks to Huyen Tue Dao for editing this post!