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 en modo de prueba. Es similar a Mockito, pero está destinada a Android Intents.

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

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:

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

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

androidTestImplementation 'androidx.test:runner:1.1.0'
    androidTestImplementation 'androidx.test:rules:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
    

Cómo escribir reglas de prueba

Antes de escribir una prueba de Espresso-Intents, configura una instancia de IntentsTestRule. Esta es una extensión de la clase ActivityTestRule y facilita el uso de las API de Espresso-Intents en las pruebas funcionales de la IU. Una IntentsTestRule inicializa Espresso-Intents antes de cada prueba con la anotación @Test y libera 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 permite interceptar intents salientes en función de ciertos criterios de coincidencia, que se definen mediante los comparadores de Hamcrest. Hamcrest te permite:

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

Espresso-Intents ofrece los métodos intended() y intending() para la validación de intents y stubbing, 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 en modo de prueba. Usando el método intended(), que es similar a Mockito.verify(), puede afirmar que se ha visto un intent determinado. Sin embargo, Espresso-Intents no elimina las respuestas a los intents, a menos que lo configures explícitamente 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"));
    }
    

Stubbing

Utilizando el método intending(), que es similar a Mockito.when(), puede 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 en la actividad en modo de prueba.

En los siguientes fragmentos de código, se implementa una prueba de ejemplo activityResult_DisplaysContactsPhoneNumber(), que verifica que, cuando un usuario inicia una actividad de "contacto" en la app en modo de prueba, 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 del ejemplo intercepta todos los intents enviados a "contacts" y sustituye sus respuestas con un resultado de ActivityResult válido, utilizando el 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 con el intent "contacts":

    Kotlin

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

    Java

        intending(toPackage("com.android.contacts")).respondWith(result);
        
  3. Verifica que la acción utilizada para iniciar la actividad produzca el resultado de stub esperado. En este caso, la prueba de ejemplo verifica que se muestra 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