Espresso-intent

Espresso-Intents è un'estensione di Espresso, che consente la convalida e lo stubbing degli intent inviati dall'applicazione sottoposta a test. È come Mockito, ma per Android Intents.

Se la tua app delega la funzionalità ad altre app o alla piattaforma, puoi utilizzare Espresso-Intents per concentrarti sulla logica della tua app, supponendo che altre app o la piattaforma funzionino correttamente. Con Espresso-Intents, puoi associare e convalidare i tuoi intenti in uscita o anche fornire risposte stub al posto di quelle effettive.

Includi Espresso-Intent nel progetto

Nel file app/build.gradle dell'app, aggiungi la seguente riga all'interno di dependencies:

Trendy

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

Kotlin

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

Espresso-Intents è compatibile solo con Espresso 2.1 e versioni successive e versione 0.3 e successive delle librerie di test di Android, quindi assicurati di aggiornare anche queste righe:

Trendy

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

Scrivere le regole di test

Prima di scrivere un test Espresso-Intents, configura un IntentsTestRule. Si tratta di un'estensione della classe ActivityTestRule e semplifica l'utilizzo delle API Espresso-Intents nei test funzionali dell'interfaccia utente. Un IntentsTestRule inizializza Espresso-Intent prima di ogni test annotato con @Test e rilascia Espresso-Intents dopo ogni esecuzione di test.

Il seguente snippet di codice è un esempio di IntentsTestRule:

Kotlin

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

Java

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

Corrispondenza

Espresso-Intents offre la possibilità di intercettare intent in uscita in base a determinati criteri di corrispondenza, definiti utilizzando i matcher Hamcrest. Hamcrest ti consente di:

  • Utilizza un matcher di intent esistente: l'opzione più semplice, che dovrebbe quasi sempre essere preferita.
  • Implementa il tuo matcher di intent: l'opzione più flessibile. Ulteriori dettagli sono disponibili nella sezione "Scrittura di matcher personalizzati" del tutorial di Hamrest.

Espresso-Intents offre rispettivamente i metodi intended() e intending() per la convalida dell'intent e lo stubbing. Entrambi prendono un oggetto Matcher<Intent> Hamcrest come argomento.

Il seguente snippet di codice mostra la convalida dell'intent che utilizza matcher di intent esistenti che corrispondono a un intent in uscita che avvia un browser:

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

Convalida intent

Espresso-Intents registra tutti gli intent che tentano di avviare attività dall'applicazione in fase di test. Utilizzando il metodo intended(), simile a Mockito.verify(), puoi affermare che un determinato intent è stato rilevato. Tuttavia, Espresso-Intents non esclude le risposte agli intent a meno che non lo configuri esplicitamente in modo da farlo.

Lo snippet di codice riportato di seguito è un test di esempio che convalida, ma non esaurisce, le risposte a un intent in uscita che avvia un'attività esterna "telefono":

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

Utilizzando il metodo intending(), simile a Mockito.when(), puoi fornire una risposta stub per le attività avviate con startActivityForResult(). Questa funzionalità è particolarmente utile per le attività esterne perché non puoi manipolare l'interfaccia utente di un'attività esterna né controllare il valore ActivityResult restituito all'attività in fase di test.

I seguenti snippet di codice implementano un test activityResult_DisplaysContactsPhoneNumber() di esempio, che verifica che quando un utente avvia un'attività di "contatto" nell'app in fase di test, viene visualizzato il numero di telefono di contatto:

  1. Crea il risultato da restituire quando viene avviata una determinata attività. Il test di esempio intercetta tutti gli intent inviati a "contacts" e spezza le relative risposte con un valore ActivityResult valido, utilizzando il codice risultatoRESULT_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 di fornire l'oggetto risultato stub in risposta a tutte le chiamate all'intent "contacts":

    Kotlin

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

    Java

    intending(toPackage("com.android.contacts")).respondWith(result);
    
  3. Verificare che l'azione utilizzata per avviare l'attività produca il risultato stub previsto. In questo caso, il test di esempio verifica che il numero di telefono "123-345-6789" venga restituito e visualizzato all'avvio dell'"attività dei contatti":

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

Ecco il test 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)));
}

Risorse aggiuntive

Per maggiori informazioni sull'utilizzo di Espresso-Intents nei test di Android, consulta le risorse seguenti.

Samples