Testare le attività dell'app

Le attività fungono da contenitori per ogni interazione utente all'interno dell'app, quindi è importante testare il comportamento delle attività dell'app durante gli eventi a livello di dispositivo come i seguenti:

  • Un'altra app, ad esempio l'app Telefono del dispositivo, interrompe l'attività della tua app.
  • Il sistema distrugge e ricrea la tua attività.
  • L'utente inserisce la tua attività in un nuovo ambiente di finestre, ad esempio Picture in picture (PIP) o multi-finestra.

In particolare, è importante assicurarsi che l'attività si comporti correttamente in risposta agli eventi descritti in Ciclo di vita dell'attività.

Questa guida descrive come valutare la capacità della tua app di mantenere l'integrità dei dati e una buona esperienza utente man mano che le attività dell'app passano attraverso diversi stati nei loro cicli di vita.

Gestire lo stato di un'attività

Un aspetto fondamentale del test delle attività della tua app consiste nel posizionarle in stati particolari. Per definire la parte "dato" dei test, utilizza istanze di ActivityScenario, che fa parte della libreria AndroidX Test. Utilizzando questa classe, puoi inserire la tua attività in stati che simulano eventi a livello di dispositivo.

ActivityScenario è un'API multipiattaforma che puoi utilizzare nei test delle unità locali e nei test di integrazione sul dispositivo. Su un dispositivo reale o virtuale, ActivityScenario fornisce la sicurezza dei thread, sincronizzando gli eventi tra il thread di strumentazione del test e il thread che esegue l'attività in fase di test.

L'API è particolarmente adatta per valutare il comportamento di un'attività in fase di test quando viene eliminata o creata. Questa sezione presenta i casi d'uso più comuni associati a questa API.

Creare un'attività

Per creare l'attività in fase di test, aggiungi il codice mostrato nel seguente snippet:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
       launchActivity<MyActivity>().use {
       }
    }
}

Dopo aver creato l'attività, ActivityScenario la sposta nello stato RESUMED. Questo stato indica che la tua attività è in esecuzione ed è visibile agli utenti. In questo stato, puoi interagire liberamente con gli elementi View della tua attività utilizzando i test dell'interfaccia utente Espresso.

Google consiglia di chiamare close sull'attività al termine del test. In questo modo, le risorse associate vengono pulite e la stabilità dei test migliora. ActivityScenario implementa Closeable, quindi puoi applicare l'estensione use o try-with-resources nel linguaggio di programmazione Java, in modo che l'attività si chiuda automaticamente.

In alternativa, puoi utilizzare ActivityScenarioRule per chiamare automaticamente ActivityScenario.launch prima di ogni test e ActivityScenario.close al termine del test. L'esempio seguente mostra come definire una regola e ottenere un'istanza di uno scenario:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule var activityScenarioRule = activityScenarioRule<MyActivity>()

    @Test fun testEvent() {
        val scenario = activityScenarioRule.scenario
    }
}

Portare l'attività a un nuovo stato

Per spostare l'attività in un altro stato, ad esempio CREATED o STARTED, chiama moveToState(). Questa azione simula una situazione in cui la tua attività viene interrotta o messa in pausa, rispettivamente, perché viene interrotta da un'altra app o da un'azione di sistema.

Un esempio di utilizzo di moveToState() è riportato nel seguente snippet di codice:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.moveToState(State.CREATED)
        }
    }
}

Determinare lo stato dell'attività corrente

Per determinare lo stato attuale di un'attività in fase di test, recupera il valore del campo state all'interno dell'oggetto ActivityScenario. È particolarmente utile controllare lo stato di un'attività in fase di test se l'attività reindirizza a un'altra attività o termina autonomamente, come illustrato nel seguente snippet di codice:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.onActivity { activity ->
              startActivity(Intent(activity, MyOtherActivity::class.java))
            }

            val originalActivityState = scenario.state
        }
    }
}

Ricrea l'attività

Quando le risorse di un dispositivo sono scarse, il sistema potrebbe eliminare un'attività, richiedendo alla tua app di ricrearla quando l'utente torna nell'app. Per simulare queste condizioni, chiama recreate():

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.recreate()
        }
    }
}

La classe ActivityScenario mantiene lo stato dell'istanza salvata dell'attività e qualsiasi oggetto annotato utilizzando @NonConfigurationInstance. Questi oggetti vengono caricati nella nuova istanza dell'attività in fase di test.

Recuperare i risultati dell'attività

Per ottenere il codice risultato o i dati associati a un'attività completata, ottieni il valore del campo result all'interno dell'oggetto ActivityScenario, come mostrato nel seguente snippet di codice:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testResult() {
        launchActivity<MyActivity>().use {
            onView(withId(R.id.finish_button)).perform(click())

            // Activity under test is now finished.

            val resultCode = scenario.result.resultCode
            val resultData = scenario.result.resultData
        }
    }
}

Azioni di attivazione nell'attività

Tutti i metodi all'interno di ActivityScenario sono chiamate di blocco, quindi l'API richiede di eseguirli nel thread di strumentazione.

Per attivare le azioni nell'attività in fase di test, utilizza i matcher di visualizzazione Espresso per interagire con gli elementi nella visualizzazione:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use {
            onView(withId(R.id.refresh)).perform(click())
        }
    }
}

Se devi chiamare un metodo sull'attività stessa, puoi farlo in modo sicuro implementando ActivityAction:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.onActivity { activity ->
              activity.handleSwipeToRefresh()
            }
        }
    }
}