Espresso-Intents is an extension to Espresso, which enables validation and stubbing of intents sent out by the application under test. It’s like Mockito, but for Android Intents.
If your app delegates functionality to other apps or the platform, you can use Espresso-Intents to focus on your own app's logic while assuming that other apps or the platform will function correctly. With Espresso-Intents, you can match and validate your outgoing intents or even provide stub responses in place of actual intent responses.
Include Espresso-Intents in your project
In your app's app/build.gradle
file, add the following line inside
dependencies
:
Groovy
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.6.1'
Kotlin
androidTestImplementation('androidx.test.espresso:espresso-intents:3.6.1')
Espresso-Intents is only compatible with Espresso 2.1+ and version 0.3+ of Android testing libraries, so make sure you update those lines as well:
Groovy
androidTestImplementation 'androidx.test:runner:1.6.1' androidTestImplementation 'androidx.test:rules:1.6.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
Kotlin
androidTestImplementation('androidx.test:runner:1.6.1') androidTestImplementation('androidx.test:rules:1.6.1') androidTestImplementation('androidx.test.espresso:espresso-core:3.6.1')
Write test rules
Before writing an Espresso-Intents test, set up an IntentsTestRule
. This is an
extension of the class ActivityTestRule
and makes it easy to use
Espresso-Intents APIs in functional UI tests. An IntentsTestRule
initializes
Espresso-Intents before each test annotated with @Test
and releases
Espresso-Intents after each test run.
The following code snippet is an example of an IntentsTestRule
:
Kotlin
@get:Rule val intentsTestRule = IntentsTestRule(MyActivity::class.java)
Java
@Rule public IntentsTestRule<MyActivity> intentsTestRule = new IntentsTestRule<>(MyActivity.class);
Match
Espresso-Intents provides the ability to intercept outgoing intents based on certain matching criteria, which are defined using Hamcrest Matchers. Hamcrest allows you to:
- Use an existing intent matcher: Easiest option, which should almost always be preferred.
- Implement your own intent matcher: Most flexible option. More details are available in the section entitled "Writing custom matchers" within the Hamcrest tutorial.
Espresso-Intents offers the intended()
and intending()
methods for intent validation and
stubbing, respectively. Both take a Hamcrest Matcher<Intent>
object as an
argument.
The following code snippet shows intent validation that uses existing intent matchers that matches an outgoing intent that starts a browser:
Kotlin
assertThat(intent).hasAction(Intent.ACTION_VIEW) assertThat(intent).categories().containsExactly(Intent.CATEGORY_BROWSABLE) assertThat(intent).hasData(Uri.parse("www.google.com")) assertThat(intent).extras().containsKey("key1") assertThat(intent).extras().string("key1").isEqualTo("value1") assertThat(intent).extras().containsKey("key2") assertThat(intent).extras().string("key2").isEqualTo("value2")
Java
assertThat(intent).hasAction(Intent.ACTION_VIEW); assertThat(intent).categories().containsExactly(Intent.CATEGORY_BROWSABLE); assertThat(intent).hasData(Uri.parse("www.google.com")); assertThat(intent).extras().containsKey("key1"); assertThat(intent).extras().string("key1").isEqualTo("value1"); assertThat(intent).extras().containsKey("key2"); assertThat(intent).extras().string("key2").isEqualTo("value2");
Validate intents
Espresso-Intents records all intents that attempt to launch activities from the
application under test. Using the intended()
method, which is similar to
Mockito.verify()
, you can assert that a given intent has been seen. However,
Espresso-Intents doesn't stub out responses to intents unless you explicitly configure
it to do so.
The following code snippet is an example test that validates, but doesn't stub out responses to, an outgoing intent that launches an external "phone" activity:
Kotlin
@Test fun validateIntentSentToPackage() { // User action that results in an external "phone" activity being launched. user.clickOnView(system.getView(R.id.callButton)) // Using a canned RecordedIntentMatcher to validate that an intent resolving // to the "phone" activity has been sent. intended(toPackage("com.android.phone")) }
Java
@Test public void validateIntentSentToPackage() { // User action that results in an external "phone" activity being launched. user.clickOnView(system.getView(R.id.callButton)); // Using a canned RecordedIntentMatcher to validate that an intent resolving // to the "phone" activity has been sent. intended(toPackage("com.android.phone")); }
Stubbing
Using the intending()
method, which is similar to Mockito.when()
, you can
provide a stub response for activities that are launched with
startActivityForResult()
. This is particularly useful for external activities
because you cannot manipulate the user interface of an external activity nor
control the ActivityResult
returned to the activity under test.
The following code snippets implement an example
activityResult_DisplaysContactsPhoneNumber()
test, which verifies that when a
user launches a "contact" activity in the app under test, the contact phone
number is displayed:
Build the result to return when a particular activity is launched. The example test intercepts all Intents sent to "contacts" and stubs out their responses with a valid
ActivityResult
, using the result codeRESULT_OK
Kotlin
val resultData = Intent() val phoneNumber = "123-345-6789" resultData.putExtra("phone", phoneNumber) val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)
Java
Intent resultData = new Intent(); String phoneNumber = "123-345-6789"; resultData.putExtra("phone", phoneNumber); ActivityResult result = new ActivityResult(Activity.RESULT_OK, resultData);
Instruct Espresso to provide the stub result object in response to all invocations of the "contacts" intent:
Kotlin
intending(toPackage("com.android.contacts")).respondWith(result)
Java
intending(toPackage("com.android.contacts")).respondWith(result);
Verify that the action used to launch the activity produces the expected stub result. In this case, the example test checks that the phone number "123-345-6789" is returned and displayed when the "contacts activity" is launched:
Kotlin
onView(withId(R.id.pickButton)).perform(click()) onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)))
Java
onView(withId(R.id.pickButton)).perform(click()); onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)));
Here is the complete activityResult_DisplaysContactsPhoneNumber()
test:
Kotlin
@Test fun activityResult_DisplaysContactsPhoneNumber() { // Build the result to return when the activity is launched. val resultData = Intent() val phoneNumber = "123-345-6789" resultData.putExtra("phone", phoneNumber) val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData) // Set up result stubbing when an intent sent to "contacts" is seen. intending(toPackage("com.android.contacts")).respondWith(result) // User action that results in "contacts" activity being launched. // Launching activity expects phoneNumber to be returned and displayed. onView(withId(R.id.pickButton)).perform(click()) // Assert that the data we set up above is shown. onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber))) }
Java
@Test public void activityResult_DisplaysContactsPhoneNumber() { // Build the result to return when the activity is launched. Intent resultData = new Intent(); String phoneNumber = "123-345-6789"; resultData.putExtra("phone", phoneNumber); ActivityResult result = new ActivityResult(Activity.RESULT_OK, resultData); // Set up result stubbing when an intent sent to "contacts" is seen. intending(toPackage("com.android.contacts")).respondWith(result); // User action that results in "contacts" activity being launched. // Launching activity expects phoneNumber to be returned and displayed. onView(withId(R.id.pickButton)).perform(click()); // Assert that the data we set up above is shown. onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber))); }
Additional resources
For more information about using Espresso-Intents in Android tests, consult the following resources.
Samples
- IntentsBasicSample:
Basic usage of
intended()
andintending()
. - IntentsAdvancedSample: Simulates a user fetching a bitmap using the camera.