Espresso-Intents

Espresso-Intents é uma extensão do Espresso, que permite validar e criar stubs de intents enviados pelo app em teste. É como o Mockito, mas para intents do Android.

Se seu app delega recursos a outros apps ou à plataforma, você pode usar o Espresso-Intents para se concentrar na lógica do próprio app, contanto que outros apps ou a plataforma funcionem corretamente. Com o Espresso-Intents, você pode combinar e validar seus intents de saída ou inclusive disponibilizar respostas de stub em vez de respostas de intent reais.

Incluir o Espresso-Intents no projeto

No arquivo app/build.gradle do seu app, adicione a seguinte linha em dependencies:

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

O Espresso-Intents é compatível apenas com o Espresso 2.1 e versões mais recentes e com versões das bibliotecas de testes do Android posteriores à 0.3. Portanto, atualize estas linhas também:

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

Programar regras de teste

Antes de programar um teste do Espresso-Intents, configure uma IntentsTestRule. Essa é uma extensão da classe ActivityTestRule que facilita o uso de APIs do Espresso-Intents em testes funcionais de IU. Um IntentsTestRule inicializa o Espresso-Intents antes de cada teste anotado com @Test e libera o Espresso-Intents após cada execução de teste.

O snippet de código a seguir é um exemplo de um IntentsTestRule.

Kotlin

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

Java

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

Correspondência

O Espresso-Intents permite interceptar os intents de saída com base em certos critérios de correspondência, que são definidos com o uso de matchers do Hamcrest. O Hamcrest permite:

  • usar um matcher de intent já existente: opção mais fácil, quase sempre preferencial;
  • implementar o próprio matcher de intent: opção mais flexível. Mais detalhes estão disponíveis na seção "Programar matchers personalizados" no Tutorial do Hamcrest (em inglês).

O Espresso-Intents oferece os métodos intended() e intending() para validar e criar stubs de intents, respectivamente. Ambos usam um objeto Matcher<Intent> do Hamcrest como argumento.

O snippet de código a seguir mostra uma validação que usa matchers de intent já existentes. Esses matchers associam uma intent de saída que inicia um 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");
    

Validar intents

Espresso-Intents registra todas as intents que tentam iniciar atividades no app em teste. Usando o método intended(), que é semelhante a Mockito.verify(), você pode declarar que uma determinada intent foi vista. No entanto, o Espresso-Intents não cria stubs de respostas para intents, a menos que você o configure explicitamente para fazer isso.

O snippet de código a seguir é um exemplo de teste que valida respostas, mas não cria stubs delas, para um intent de saída que inicia uma atividade "phone" externa:

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

Criar stubs

Usando o método intending(), que é semelhante a Mockito.when(), é possível fornecer uma resposta de stub para atividades iniciadas com startActivityForResult(). Isso é particularmente útil para atividades externas, porque não é possível manipular a interface do usuário de uma atividade externa nem controlar o ActivityResult retornado para a atividade em teste.

Os snippets de código a seguir implementam um exemplo de teste activityResult_DisplaysContactsPhoneNumber(), que verifica se o número de telefone do contato é exibido quando um usuário inicia uma atividade de “contato” no app.

  1. Crie o resultado a ser retornado quando uma atividade específica for iniciada. O teste de exemplo intercepta todas as intents enviadas para os "contatos" e compila as respostas com um ActivityResult válido, usando o 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. Instrua o Espresso a disponibilizar o objeto de resultado de stub em resposta a todas as invocações do intent "contacts":

    Kotlin

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

    Java

        intending(toPackage("com.android.contacts")).respondWith(result);
        
  3. Verifique se a ação usada para iniciar a atividade produz o resultado de stub esperado. Nesse caso, o teste de exemplo verifica se o número de telefone "123-345-6789" é retornado e exibido quando a atividade "contacts" é iniciada:

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

Este é o teste activityResult_DisplaysContactsPhoneNumber() completo:

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

Outros recursos

Para saber mais sobre o uso do Espresso-Intents em testes do Android, consulte os recursos a seguir.

Amostras