Testare le attività dell'app

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

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

In particolare, è importante verificare che l'attività si comporti correttamente in risposta agli eventi descritti nella sezione Il 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 durante la transizione delle attività dell'app attraverso stati diversi nei loro cicli di vita.

Controllare lo stato di un'attività

Un aspetto chiave del test delle attività della tua app consiste nel posizionare le attività dell'app in determinati stati. Per definire questa parte "data" dei tuoi test, utilizza le istanze di ActivityScenario, che fanno parte della libreria di AndroidX Test. Utilizzando questa lezione, puoi posizionare l'attività in stati che simulano eventi a livello di dispositivo.

ActivityScenario è un'API multipiattaforma che puoi utilizzare sia nei test delle unità locali sia nei test di integrazione on-device. Su un dispositivo reale o virtuale, ActivityScenario offre 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 nello snippet seguente:

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

Dopo aver creato l'attività, ActivityScenario la trasferisce allo stato RESUMED. Questo stato indica che l'attività è in esecuzione ed è visibile agli utenti. In questo stato, puoi interagire con gli elementi View della tua attività utilizzando i test della UI di Espresso.

Google consiglia di chiamare close nell'attività al termine del test. Questo esegue la pulizia delle risorse associate e migliora la stabilità dei test. 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 durante la rimozione del test. L'esempio seguente mostra come definire una regola e ricavarne l'istanza di uno scenario:

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

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

Porta l'attività a un nuovo stato

Per portare l'attività a un altro stato, ad esempio CREATED o STARTED, chiama moveToState(). Questa azione simula una situazione in cui l'attività viene interrotta o messa in pausa, rispettivamente, perché è stata 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, ottieni il valore del campo state all'interno dell'oggetto ActivityScenario. È particolarmente utile controllare lo stato di un'attività sottoposta a test se l'attività reindirizza a un'altra attività o si conclude autonomamente, come mostrato 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 scarseggia, il sistema potrebbe distruggere un'attività, richiedendo all'app di ricrearla quando l'utente torna all'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 tutti gli oggetti annotati utilizzando @NonConfigurationInstance. Questi oggetti vengono caricati nella nuova istanza dell'attività in fase di test.

Recuperare i risultati di un'attività

Per ottenere il codice risultato o i dati associati a un'attività terminata, 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
        }
    }
}

Attiva azioni nell'attività

Tutti i metodi all'interno di ActivityScenario bloccano le chiamate, quindi l'API richiede che tu le esegua nel thread della strumentazione.

Per attivare le azioni nell'attività sottoposta a test, utilizza i matcher della vista Espresso per interagire con gli elementi della vista:

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

Tuttavia, se devi chiamare un metodo sull'attività stessa, puoi farlo in sicurezza implementando ActivityAction:

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