Test delle interfacce con Espresso

25 gennaio 2017

In questa lezione, proseguiremo lo studio di Espresso come meccanismo di test per le interfacce utente. Ne abbiamo già visto i principi fondamentali, mentre adesso aggiungeremo qualche funzionalità alla nostra app di prova, in modo da poter sperimentare ulteriormene questo framework.

Cosa sottoporremo a test

L’app da collaudare ha un’Activity principale che contiene una ListView in cui vengono mostrati i dati dei soggetti da registrare. Le due funzionalità che metteremo sotto osservazione grazie ad Espresso sono:

  • l’apertura di una finestra di dialogo, al click del Floating Action Button, che offrirà un form per l’inserimento dei dati di un nuovo soggetto;

    Figura 1. Inserimento dati (click per ingrandire)

    Inserimento dati
  • l’apertura di una nuova Activity al click di una singola riga della ListView, al fine di mostrare una scheda riepilogativa di un singolo soggetto registrato;

    Figura 2. Visualizzazione scheda (click per ingrandire)

    Visualizzazione scheda

Attiveremo tramite Espresso entrambe queste funzionalità, e ne valuteremo gli effetti.

Primo test: inserimento tramite form

Considerando che il form su cui dobbiamo svolgere il test si trova in una finestra di dialogo, possiamo innanzitutto verificare che il Floating Action Button sia correttamente associato ad un’azione che ne inneschi effettivamente l’apertura. Il seguente breve test verifica proprio questo: produciamo un click sul pulsante flottante, e controlliamo se risulta visibile il layout che compone l’interfaccia utente del form al quale abbiamo assegnato esplicitamente un ID (R.id.dialog_layout):

    @Test
    public void openDialog()
    {
        onView(withId(R.id.fab)).perform(click());
        onView(withId(R.id.dialog_layout)).check(matches(isDisplayed()));
    }

Potremo innestare questo test nella struttura di classe vista nella lezione precedente.

Il test più completo che abbiamo intenzione di svolgere si articola invece su più fasi:

  • click sul Floating Action Button, come abbiamo visto poco fa;
  • inserimento di testo all’interno delle EditText tramite il metodo typeText;
  • salvataggio dei dati mediante pressione sul pulsante Salva;
  • verifica dell’avvenuto inserimento leggendo quanto mostrato nella TextView presente all’ultima riga della ListView: se tutto è andato a buon fine, vi dovremmo ritrovare proprio i testi che abbiamo appena passato.
    @Test
    public void insertData()
    {

	// 1. le stringhe che inseriremo nel form
        String nomePerTest="Enrico";
        String cognomePerTest="Bianchi";
        String etaPerTest="28";

	// 2. cosa ci aspettiamo di leggere nell'ultima riga della ListView
        String stringaAttesa=cognomePerTest+" "+nomePerTest+" - età "+etaPerTest;

	// 3. click sul FAB
        onView(withId(R.id.fab)).perform(click());

	// 4. inserimento testi nel form
        onView(withId(R.id.nome)).perform(typeText(nomePerTest));
        onView(withId(R.id.cognome)).perform(typeText(cognomePerTest));
        onView(withId(R.id.eta)).perform(typeText(etaPerTest));

	// 5. salvataggio mediante click su pulsante "Salva"
        onView(withId(android.R.id.button1)).perform(click());

	// 6. leggiamo la nuova dimensione della ListView (dovrebbe essere aumentata)
        int quanti=((ListView)mIntentActivityRule.getActivity().findViewById(R.id.listView)).getCount();

	// 7. verifichiamo se ciò che c'è scritto nell'ultima riga della ListView equivale a stringaAttesa
        onData(anything()).inAdapterView(withId(R.id.listView))
                .atPosition(quanti-1)
                .onChildView(withId(R.id.testo))
                .check(matches(withText(containsString(stringaAttesa))));
    }

Il test lavora interamente sull’interfaccia utente, sia a livello di inserimento sia di verifica, ma coinvolge i funzionamenti interni dell’Adapter, risultando pertanto piuttosto completo.

Secondo test: invocazione di Intent

Al click di una riga della ListView viene aperta una seconda Activity che mostra i dati relativi ad un soggetto: tali informazioni dovranno essere associate all’Intent. Espresso permette di svolgere diversi test sul funzionamento di un Intent, e qui ne proveremo alcuni. Per fare ciò però serve, per prima cosa, inserire un’ulteriore libreria tra le dipendenze, senza dimenticare di sincronizzare il progetto con i file di configurazione di Gradle:

dependencies {
	...
	androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
	...
}

Fatto questo, potremo utilizzare apposite classi per il testing. Osserviamo prima come funziona, nell’app di prova, il passaggio alla seconda Activity. Il layout che utilizziamo per rappresentare la struttura della riga della ListView ha un attributo onClick che indica quale metodo chiamare quando si esegue un tap su una riga:

<RelativeLayout
    ...
    android:onClick="mostraDettagli">

All’interno della classe MainActivity, inoltre, troviamo il codice che attiva l’Intent (non prima di aver recuperato l’oggetto di classe Persona relativo alla riga selezionata, e averlo allegato al pacchetto di Extras). Si noti che, per semplicità, si è definita la classe Persona come implementazione di Serializable:

public class MainActivity extends AppCompatActivity {
    ...

    public final static String PERSONA_EXTRA="persona_extra"

    ...

    public void mostraDettagli(View v)
    {
        int pos=listView.getPositionForView(v);
        Persona p=adapter.getItem(pos);
        Intent i=new Intent(this, DetailActivity.class);
        i.putExtra(PERSONA_EXTRA, (Serializable) p);
        startActivity(i);
    }

   ...

}

All’interno dei test, dovremo:

  • definire una regola sfruttando la classe IntentsTestRule, estensione di ActivityTestRule (già vista nella lezione precedente), per inizializzare il meccanismo di verifica degli Intent di Espresso prima dell’attivazione dei metodi contrassegnati con l’annotation @Test;
  • eseguire la cosiddetta Intent Verification, all’interno dei metodi adibiti ai test, sfruttando il metodo intended che applicherà Matcher agli Intent rilevati. I Matcher da utilizzare saranno di classe IntentMatchers.

Vediamo subito un esempio:

public class Intent_Test {

    @Rule
    public IntentsTestRule<MainActivity> mIntentActivityRule = new IntentsTestRule<>(MainActivity.class);

    @Test
    public void openNewActivity()
    {
        onData(anything())
           .inAdapterView(withId(R.id.listView))
                .atPosition(0)
                   .perform(click());

        intended(toPackage("it.html.esempio_espresso02"));
    }

}

Con la prima riga, viene eseguito un click sul primo elemento della ListView (che daremo per scontato esista), e successivamente con intended eseguiamo il controllo verificando che l’Activity attivata faccia parte del package it.html.esempio_espresso02.

Altro metodo utile consiste nella verifica della presenza di un Extra caratterizzato da una determinata chiave:

    @Test
    public void checkExtra()
    {
        onData(anything())
                .inAdapterView(withId(R.id.listView))
                .atPosition(0)
                .perform(click());
        intended(hasExtraWithKey(MainActivity.PERSONA_EXTRA));
    }

Note conclusive

Come si può immaginare, gli strumenti a disposizione di Espresso sono molti di più di quelli visti in queste lezioni, ma abbiamo comunque implementato i principali meccanismi di base per i test più comuni. Per tutto il resto, si può consultare la documentazione allegata al framework e alle varie librerie in ecco incluse. Si ricordi sempre l’utilità di poter lanciare anche test singoli: sarà sufficiente fare click con il tasto destro del mouse all’interno di un metodo e selezionare il relativo comando Run.

Figura 3. Avvio di un singolo test (click per ingrandire)

Avvio di un singolo test

Inoltre, si cerchi sempre di verificare la bontà di un test non accontentandosi del suo successo, ma verificando che esso fallisca con dati volutamente errati.

Tutte le lezioni

1 ... 66 67 68 ... 85

Se vuoi aggiornamenti su Test delle interfacce con Espresso inserisci la tua e-mail nel box qui sotto:
Tags:
 
X
Se vuoi aggiornamenti su Test delle interfacce con Espresso

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy