Sincronizzare i test

I test della scrittura sono sincronizzati per impostazione predefinita con la tua UI. Quando chiami un'assertion o un'azione con ComposeTestRule, il test viene sincronizzato in anticipo, attendendo che la struttura dell'interfaccia utente sia inattiva.

In genere, non devi intraprendere alcuna azione. Tuttavia, esistono alcuni casi limite di cui dovresti essere a conoscenza.

Quando un test è sincronizzato, l'app Compose viene avanzata in tempo utilizzando un orologio virtuale. Ciò significa che i test di Compose non vengono eseguiti in tempo reale, quindi possono essere superati il più rapidamente possibile.

Tuttavia, se non utilizzi i metodi che sincronizzano i test, non verrà eseguita alcuna ricomposizione e la UI apparirà in pausa.

@Test
fun counterTest() {
    val myCounter = mutableStateOf(0) // State that can cause recompositions.
    var lastSeenValue = 0 // Used to track recompositions.
    composeTestRule.setContent {
        Text(myCounter.value.toString())
        lastSeenValue = myCounter.value
    }
    myCounter.value = 1 // The state changes, but there is no recomposition.

    // Fails because nothing triggered a recomposition.
    assertTrue(lastSeenValue == 1)

    // Passes because the assertion triggers recomposition.
    composeTestRule.onNodeWithText("1").assertExists()
}

Tieni presente che questo requisito si applica solo alle gerarchie di Compose e non al resto dell'app.

Disattivare la sincronizzazione automatica

Quando chiami un'asserzione o un'azione tramite ComposeTestRule, come assertExists(), il test viene sincronizzato con l'interfaccia utente di Compose. In alcuni casi, è possibile che tu voglia interrompere la sincronizzazione e controllare l'orologio autonomamente. Ad esempio, puoi controllare il tempo per acquisire screenshot accurati di un'animazione in un punto in cui l'interfaccia utente è ancora occupata. Per disattivare la sincronizzazione automatica, imposta la proprietà autoAdvance in mainClock su false:

composeTestRule.mainClock.autoAdvance = false

In genere, puoi avanzare di nuovo tu stesso. Puoi avanzare esattamente di un frame con advanceTimeByFrame() o di una durata specifica con advanceTimeBy():

composeTestRule.mainClock.advanceTimeByFrame()
composeTestRule.mainClock.advanceTimeBy(milliseconds)

Risorse inattive

Compose può sincronizzare i test e l'UI in modo che ogni azione e asserzione venga eseguita in stato inattivo, in attesa o avanzando l'orologio secondo necessità. Tuttavia, alcune operazioni asincrone i cui risultati influiscono sullo stato dell'interfaccia utente possono essere eseguite in background mentre il test non ne è a conoscenza.

Crea e registra queste risorse inutilizzate nel test in modo che vengano prese in considerazione per decidere se l'app sottoposta a test è occupata o inattiva. Non devi intraprendere alcuna azione a meno che tu non debba registrare ulteriori risorse inattive, ad esempio se esegui un job in background non sincronizzato con Espresso o Compose.

Questa API è molto simile alle risorse inattive di Espresso per indicare se il soggetto sottoposto a test è inattivo o occupato. Utilizza la regola di test di Compose per registrare l'implementazione di IdlingResource.

composeTestRule.registerIdlingResource(idlingResource)
composeTestRule.unregisterIdlingResource(idlingResource)

Sincronizzazione manuale

In alcuni casi, devi sincronizzare l'UI di Compose con altre parti del test o con l'app che stai testando.

La funzione waitForIdle() attende che Compose sia inattivo, ma dipende dalla proprietà autoAdvance:

composeTestRule.mainClock.autoAdvance = true // Default
composeTestRule.waitForIdle() // Advances the clock until Compose is idle.

composeTestRule.mainClock.autoAdvance = false
composeTestRule.waitForIdle() // Only waits for idling resources to become idle.

Tieni presente che in entrambi i casi waitForIdle() attende anche i passaggi di disegno e layout in attesa.

Inoltre, puoi avanzare l'orologio fino a quando una determinata condizione non viene soddisfatta con advanceTimeUntil().

composeTestRule.mainClock.advanceTimeUntil(timeoutMs) { condition }

Tieni presente che la condizione specificata dovrebbe controllare lo stato che può essere influenzato da questo quadrante orologio (funziona solo con lo stato Scrivi).

Attendi le condizioni

Qualsiasi condizione che dipende da lavori esterni, come il caricamento dei dati o la misurazione o il disegno di Android (ovvero, misurazione o disegno all'esterno di Compose), dovrebbe utilizzare un concetto più generale come waitUntil():

composeTestRule.waitUntil(timeoutMs) { condition }

Puoi anche utilizzare uno degli helper di waitUntil:

composeTestRule.waitUntilAtLeastOneExists(matcher, timeoutMs)

composeTestRule.waitUntilDoesNotExist(matcher, timeoutMs)

composeTestRule.waitUntilExactlyOneExists(matcher, timeoutMs)

composeTestRule.waitUntilNodeCount(matcher, count, timeoutMs)

Risorse aggiuntive

  • App di test su Android: la pagina di destinazione principale per i test di Android offre una visione più ampia sulle tecniche e sui concetti fondamentali dei test.
  • Nozioni di base sui test: scopri di più sui concetti fondamentali alla base del test di un'app per Android.
  • Test locali: puoi eseguire alcuni test in locale, sulla tua workstation.
  • Test strumentati: è buona norma eseguire anche test con strumentazione. ovvero test eseguiti direttamente sul dispositivo.
  • Integrazione continua: l'integrazione continua consente di integrare i test nella pipeline di deployment.
  • Prova dimensioni dello schermo diverse: dato che sono disponibili molti dispositivi per gli utenti, dovresti testare schermi di dimensioni diverse.
  • Espresso: sebbene destinato alle UI basate su View, la conoscenza di Espresso può comunque essere utile per alcuni aspetti dei test di Compose.