Intents d'Espresso

Espresso-Intents est une extension d'Espresso qui permet de valider et de boucher les intents envoyés par l'application testée. Il s'agit d'un outil semblable à Mockito, mais pour les intents Android.

Si votre application délègue des fonctionnalités à d'autres applications ou à la plate-forme, vous pouvez utiliser Espresso-Intents pour vous concentrer sur la logique de votre application, en supposant que les autres applications ou la plate-forme fonctionneront correctement. Espresso-Intents vous permet d'associer et de valider vos intents sortants, et même de fournir des bouchons de réponse à la place des réponses d'intent réelles.

Inclure Espresso-Intents dans votre projet

Dans le fichier app/build.gradle de votre application, ajoutez la ligne suivante à l'intérieur de dependencies :

Groovy

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

Kotlin

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

Espresso-Intents n'est compatible qu'avec Espresso 2.1 et les bibliothèques de test Android version 0.3 ou ultérieure. Assurez-vous donc de mettre à jour ces lignes également :

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

Écrire des règles de test

Avant d'écrire un test Espresso-Intents, configurez un IntentsTestRule. Il s'agit d'une extension de la classe ActivityTestRule qui facilite l'utilisation des API Espresso-Intents dans les tests d'UI fonctionnels. Un IntentsTestRule initialise Espresso-Intents avant chaque test annoté avec @Test et libère Espresso-Intents après chaque exécution de test.

L'extrait de code suivant est un exemple de IntentsTestRule :

Kotlin

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

Java

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

Correspondance

Espresso-Intents permet d'intercepter les intents sortants en fonction de certains critères de correspondance, qui sont définis à l'aide de Hamcrest Matchers. Hamcrest vous permet de :

  • Utiliser un détecteur d'intentions existant : il s'agit de l'option la plus simple, qui devrait presque toujours être privilégiée.
  • Implémenter votre propre outil de mise en correspondance des intentions : il s'agit de l'option la plus flexible. Pour en savoir plus, consultez la section "Writing custom matchers" (Écrire des comparateurs personnalisés) du tutoriel Hamcrest.

Espresso-Intents propose les méthodes intended() et intending() pour la validation et la simulation d'intentions, respectivement. Les deux prennent un objet Hamcrest Matcher<Intent> comme argument.

L'extrait de code suivant montre la validation d'intent qui utilise des vérificateurs d'intent existants correspondant à un intent sortant qui démarre un navigateur :

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

Valider les intents

Espresso-Intents enregistre toutes les intentions qui tentent de lancer des activités à partir de l'application testée. À l'aide de la méthode intended(), qui est semblable à Mockito.verify(), vous pouvez affirmer qu'une intention donnée a été vue. Toutefois, Espresso-Intents ne crée pas de bouchons de réponse aux intents, sauf si vous le configurez explicitement pour le faire.

L'extrait de code suivant est un exemple de test qui valide une intention sortante lançant une activité "téléphone" externe, mais ne simule pas les réponses à cette intention :

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

En utilisant la méthode intending(), qui est semblable à Mockito.when(), vous pouvez fournir une réponse de stub pour les activités lancées avec startActivityForResult(). Cela est particulièrement utile pour les activités externes, car vous ne pouvez pas manipuler l'interface utilisateur d'une activité externe ni contrôler le ActivityResult renvoyé à l'activité en cours de test.

Les extraits de code suivants implémentent un exemple de test activityResult_DisplaysContactsPhoneNumber(), qui vérifie que le numéro de téléphone du contact s'affiche lorsqu'un utilisateur lance une activité "contact" dans l'application testée :

  1. Créez le résultat à renvoyer lorsqu'une activité spécifique est lancée. L'exemple de test intercepte toutes les intentions envoyées à "contacts" et simule leurs réponses avec un ActivityResult valide, en utilisant le code de résultat 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. Indiquez à Espresso de fournir l'objet de résultat du stub en réponse à toutes les invocations de l'intention "contacts" :

    Kotlin

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

    Java

    intending(toPackage("com.android.contacts")).respondWith(result);
  3. Vérifiez que l'action utilisée pour lancer l'activité produit le résultat de stub attendu. Dans ce cas, l'exemple de test vérifie que le numéro de téléphone 123-345-6789 est renvoyé et affiché lorsque l'activité "contacts" est lancée :

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

Voici le test activityResult_DisplaysContactsPhoneNumber() complet :

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

Ressources supplémentaires

Pour en savoir plus sur l'utilisation d'Espresso-Intents dans les tests Android, consultez les ressources suivantes.

Exemples