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.

Test delle attività in Compose

Quando testi un'app creata con Jetpack Compose, in genere utilizzi createAndroidComposeRule per avviare l'attività e interagire con i componenti dell'interfaccia utente.

Tuttavia, il test degli eventi a livello di dispositivo, come le modifiche alla configurazione o l'attività messa in background o eliminata dal sistema, richiede di manipolare direttamente il ciclo di vita dell'attività. Per farlo, utilizzi il framework ActivityScenario sottostante.

La regola di test Scrivi gestisce e gestisce automaticamente questo scenario. In questa guida vedrai il seguente pattern utilizzato per colmare il divario tra i test dell'UI moderni e la gestione standard del ciclo di vita:

@get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()

@Test fun testEvent() {
    val scenario = composeTestRule.activityRule.scenario

    // ...
}

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, 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 thread safety, 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 porta allo stato RESUMED. Questo stato indica che la tua attività è in esecuzione ed è visibile agli utenti. In questo stato, puoi interagire con i composable dell'attività utilizzando le API di test di Compose.

Google consiglia di chiamare close sull'attività al termine del test. In questo modo vengono pulite le risorse associate e viene migliorata la stabilità dei test. ActivityScenario implementa Closeable, quindi puoi applicare l'estensione use in modo che l'attività si chiuda automaticamente.

In alternativa, puoi utilizzare createAndroidComposeRule per avviare automaticamente l'attività prima di ogni test, gestire l'eliminazione e concederti l'accesso sia ai metodi di test dell'interfaccia utente Compose sia a ActivityScenario sottostante. L'esempio seguente mostra come definire una regola e ottenere un'istanza di uno scenario da questa:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test fun testEvent() {
        val scenario = composeTestRule.activityRule.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 l'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. Utilizzando createAndroidComposeRule, puoi attivare facilmente l'azione UI che termina l'attività, come mostrato nello snippet di codice seguente:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test fun testResult() {
        composeTestRule.onNodeWithTag("finish_button").performClick()

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

Azioni attivatore 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 le API di test Compose per interagire con i tuoi composable:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test fun testEvent() {
        composeTestRule.onNodeWithText("Refresh").performClick()
    }
}

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

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

Risorse aggiuntive

Per saperne di più sui test, consulta le seguenti risorse aggiuntive:

Documentazione