Espresso-Intents

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

Se o app delegar funcionalidades a outros apps ou à plataforma, você pode usar o Espresso-Intents para se concentrar na lógica do próprio app, supondo que outros apps ou a plataforma funcionem corretamente. Com o Espresso-Intents, é possível combinar e validar intents de saída ou fornecer 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 dentro de dependencies:

Groovy

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

Kotlin

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

O Espresso-Intents é compatível apenas com o Espresso 2.1 e versões mais recentes e com a versão 0.3 ou mais recente das bibliotecas de teste do Android. Portanto, atualize essas linhas também:

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

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 da interface. Uma IntentsTestRule inicializa o Espresso-Intents antes de cada teste anotado com @Test e libera 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 intents de saída com base em determinados critérios de correspondência, que são definidos usando matchers do Hamcrest. O Hamcrest permite:

  • Usar um matcher de intent já existente: opção mais fácil, que quase sempre é preferível.
  • implementar o próprio matcher de intent: opção mais flexível. Mais detalhes estão disponíveis na seção "Como escrever matchers personalizados" no Tutorial do Hamcrest.

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

O snippet de código a seguir mostra a validação de intents que usam matchers de intent existentes que correspondem a 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

O 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 abaixo é um exemplo de teste que valida, mas não cria stubs de respostas para uma intent de saída que inicia uma atividade externa "phone":

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 abaixo implementam um exemplo de teste activityResult_DisplaysContactsPhoneNumber(), que verifica se, quando um usuário inicia uma atividade de "contato" no app em teste, o número de telefone de contato é mostrado:

  1. Crie o resultado a ser retornado quando uma atividade específica for iniciada. O teste de exemplo intercepta todas as intents enviadas para "contatos" e apaga 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 fornecer o objeto de resultado de stub em resposta a todas as invocações da 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 de contatos" é 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.

Exemplos