Sincronizzare i test

I test di composizione vengono sincronizzati per impostazione predefinita con l'interfaccia utente. Quando chiami un'affermazione o un'azione con ComposeTestRule, il test viene sincronizzato in anticipo, in attesa che l'albero dell'interfaccia utente sia inattivo.

In genere, non è richiesta alcuna azione da parte tua. Tuttavia, ci sono alcuni casi limite di cui dovresti essere a conoscenza.

Quando un test viene sincronizzato, l'app Compose viene avanzata nel tempo utilizzando un orologio virtuale. Ciò significa che i test di composizione 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 ricompozione e l'interfaccia utente sembrerà essere 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 composizione e non al resto dell'app.

Disattivare la sincronizzazione automatica

Quando chiami un'affermazione o un'azione tramite ComposeTestRule, ad esempio assertExists(), il test viene sincronizzato con l'interfaccia utente di Compose. In alcuni casi, potresti voler interrompere questa 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 sarebbe ancora occupata. Per disattivare la sincronizzazione automatica, imposta la proprietà autoAdvance in mainClock su false:

composeTestRule.mainClock.autoAdvance = false

In genere, poi avanzi manualmente l'ora. Puoi avanzare di esattamente un fotogramma 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'interfaccia utente in modo che ogni azione e asserzione venga eseguita in uno stato inattivo, in attesa o facendo avanzare l'orologio in base alle esigenze. Tuttavia, alcune operazioni asincrone i cui risultati influiscono sullo stato dell'interfaccia utente possono essere eseguite in background senza che il test ne sia a conoscenza.

Crea e registra queste risorse inattive nel test in modo che vengano prese in considerazione quando decidi se l'app in test è occupata o inattiva. Non è necessario intervenire, a meno che non sia necessario registrare risorse inattive aggiuntive, 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 l'oggetto sottoposto a test è inattivo o occupato. Utilizza la regola di test Composizione per registrare l'implementazione del IdlingResource.

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

Sincronizzazione manuale

In alcuni casi, devi sincronizzare l'interfaccia utente di Compose con altre parti del test o dell'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 le passate di disegno e layout in attesa.

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

composeTestRule.mainClock.advanceTimeUntil(timeoutMs) { condition }

Tieni presente che la condizione specificata deve controllare lo stato che può essere interessato da questo timer (funziona solo con lo stato Scrittura).

Attendi condizioni

Qualsiasi condizione che dipende da un'operazione esterna, come il caricamento dei dati o le misurazioni o i disegni di Android (ovvero misurazioni o disegni esterni a Compose), deve utilizzare un concetto più generale come waitUntil():

composeTestRule.waitUntil(timeoutMs) { condition }

Puoi anche utilizzare uno degli waitUntil helper:

composeTestRule.waitUntilAtLeastOneExists(matcher, timeoutMs)

composeTestRule.waitUntilDoesNotExist(matcher, timeoutMs)

composeTestRule.waitUntilExactlyOneExists(matcher, timeoutMs)

composeTestRule.waitUntilNodeCount(matcher, count, timeoutMs)

Risorse aggiuntive

  • Testare le app su Android: la pagina di destinazione principale dei test Android offre una visione più ampia delle nozioni di base e delle tecniche di 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 localmente, sulla tua workstation.
  • Test con strumenti: è buona prassi eseguire anche test con strumenti. ovvero i test eseguiti direttamente sul dispositivo.
  • Integrazione continua: l'integrazione continua ti consente di integrare i test nella pipeline di deployment.
  • Esegui test su diverse dimensioni dello schermo: con così tanti dispositivi a disposizione degli utenti, devi testare diverse dimensioni dello schermo.
  • Espresso: sebbene sia destinato alle UI basate su visualizzazioni, le conoscenze di Espresso possono essere utili per alcuni aspetti dei test di Compose.