Espresso-Intents

Espresso-Intents es una extensión de Espresso, que permite la validación y el stubbing de los intents enviados por la aplicación sometida a prueba. Es como Mockito, pero para Intents de Android.

Si tu app delega la funcionalidad a otras apps o a la plataforma, puedes usar Espresso-Intents para concentrarte en la lógica de tu app y asumir que otras apps o la plataforma funcionarán correctamente. Con Espresso-Intents, puedes hacer coincidir y validar los intents salientes o incluso proporcionar respuestas de stub en lugar de respuestas de intents reales.

Cómo incluir Espresso-Intents en tu proyecto

En el archivo app/build.gradle de tu app, agrega la siguiente línea dentro de dependencies:

Groovy

androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0'

Kotlin

androidTestImplementation('androidx.test.espresso:espresso-intents:3.4.0')

Espresso-Intents solo es compatible con Espresso 2.1 y versiones posteriores, y con la versión 0.3 o posterior de las bibliotecas de prueba de Android, así que asegúrate de actualizar también esas líneas:

Groovy

androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test:rules:1.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

Kotlin

androidTestImplementation('androidx.test:runner:1.4.0')
androidTestImplementation('androidx.test:rules:1.4.0')
androidTestImplementation('androidx.test.espresso:espresso-core:3.4.0')

Cómo escribir reglas de prueba

Antes de escribir una prueba de Espresso-Intents, configura una IntentsTestRule. Esta es una extensión de la clase ActivityTestRule y facilita el uso de las APIs de Espresso-Intents en pruebas funcionales de la IU. Un IntentsTestRule inicializa Espresso-Intents antes de cada prueba anotada con @Test y lanza Espresso-Intents después de cada ejecución de prueba.

El siguiente fragmento de código es un ejemplo de una IntentsTestRule:

Kotlin

@get:Rule
val intentsTestRule = IntentsTestRule(MyActivity::class.java)

Java

@Rule
public IntentsTestRule<MyActivity> intentsTestRule =
    new IntentsTestRule<>(MyActivity.class);

Coincidencia

Espresso-Intents proporciona la capacidad de interceptar intents salientes en función de ciertos criterios de coincidencia, que se definen mediante los comparadores de Hamcrest. Hamcrest te permite hacer lo siguiente:

  • Usar un comparador de intents existente: Es la opción más fácil, que casi siempre será la preferida.
  • Implementar tu propio buscador de coincidencias de intent: es la opción más flexible. Para obtener más información, consulta la sección titulada "Cómo escribir comparadores personalizados" del instructivo de Hamcrest.

Espresso-Intents ofrece los métodos intended() y intending() para la validación y la creación de stubs para intents, respectivamente. Ambos toman un objeto Matcher<Intent> de Hamcrest como argumento.

En el siguiente fragmento de código, se muestra la validación de intents que utilizan comparadores de intents existentes que coinciden con un intent saliente que inicia un navegador:

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");

Cómo validar intents

Espresso-Intents registra todos los intents que intentan iniciar actividades desde la aplicación que se está probando. Con el método intended(), que es similar a Mockito.verify(), puedes confirmar que se vio un intent determinado. Sin embargo, Espresso-Intents no elimina las respuestas a los intents, a menos que lo configures de forma explícita para hacerlo.

El siguiente fragmento de código es una prueba de ejemplo que valida, pero no elimina las respuestas a un intent saliente que inicia una actividad externa de "teléfono":

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"));
}

Cómo implementar stubs

Con el método intending(), que es similar a Mockito.when(), puedes proporcionar una respuesta de stub para las actividades que se inician con startActivityForResult(). Esto es particularmente útil para actividades externas porque no puedes manipular la interfaz de usuario de una actividad externa ni controlar el ActivityResult que se muestra a la actividad en prueba.

En los siguientes fragmentos de código, se implementa una prueba de activityResult_DisplaysContactsPhoneNumber() de ejemplo, que verifica que, cuando un usuario inicia una actividad de "contacto" en la app que se está probando, se muestra el número de teléfono de contacto:

  1. Compila el resultado que se mostrará cuando se inicie una actividad en particular. La prueba de ejemplo intercepta todos los intents enviados a "contactos" y envía sus respuestas con un ActivityResult válido a través del código de resultado RESULT_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);
    
  2. Indica a Espresso que proporcione el objeto de resultado de stub en respuesta a todas las invocaciones del intent "contacts":

    Kotlin

    intending(toPackage("com.android.contacts")).respondWith(result)
    

    Java

    intending(toPackage("com.android.contacts")).respondWith(result);
    
  3. Verifica que la acción que se usó para iniciar la actividad produzca el resultado de stub esperado. En este caso, la prueba de ejemplo verifica que se muestre el número de teléfono "123-345-6789" cuando se inicia la "actividad de contactos":

    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)));
    

Esta es la prueba completa de activityResult_DisplaysContactsPhoneNumber():

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)));
}

Recursos adicionales

Para obtener más información sobre el uso de Espresso-Intents en las pruebas de Android, consulta los siguientes recursos.

Ejemplos