A few weeks ago, I wrote a basic introduction on how to use Espresso to test the UI of an Android application. However, when I went to write instrumentation tests for Aftermath, I ran into trouble testing things that exist outside my application’s process. For example, what do you do when your app needs to use the Android Intent system to call upon the dialer or the browser, or pick a contact with the contact picker? What about testing a share action? Because these apps run outside your application itself, you can’t use Espresso to interact with them. So how can you test your app’s behavior? You can either use Espresso-Intents or UI Automator (but that’s another show).
The Setup
Setting up Espresso-Intents is dead simple if you’re already using Espresso. Make sure you’re already depending on Espresso, the rules, and the runner and then add the dependency:
1
|
|
The Tests
Let’s imagine that you had an application with a button to launch the contact picker, which would then show the contact Uri
of the selected contact in a text view. Not only would this be hard to test because you are leaving your own application’s process, but you don’t even know if your test can rely on any contacts even existing on the test device (not to mention not knowing which app is registered to handle the contact-picking Intent itself). Fortunately we can use Espresso-Intents to stub out the response for activities that are launched with startActivityForResult
.
Here’s what that might look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Using the intending
API, we can respond with our mock ActivityResult
data. If you’ve used Mockito before, this stubbing will look very familiar to the when
/respondWith
methods. In this example, we’re going to stub any Intents for the ACTION_PICK
Intent with the CONTENT_URI
data set to return a particular hard-coded Uri.
So this is great — our test no longer depends on any particular contact picker app, or any contacts even being present on the test device. But what do we do if we want to verify that a particular outgoing intent is launched with some given extras or data?
Let’s say our sample app had an input field that would take a phone number, with a button to start the dialer to call that number. (Yes, I do realize that this application would likely not receive any venture capital funding).
All we have to do is use the intended
API, which is most similar to Mockito’s verify
method. A sample of this might look like the following:
1 2 3 4 5 6 |
|
In this case, we’re just going to verify that the intended Intent had the right action and the right data that we’d expect to hand off to the dialer.
And you’ll notice that the Espresso-Intents package includes handy Hamcrest matchers that you can use for things like Strings on the different parts of the Intent.
Now go forth and test those inter-app component interactions!
The sample code for this blog post can be found here.