Tests synchronisieren

Erstellungstests werden standardmäßig mit Ihrer UI synchronisiert. Wenn Sie eine Assertion oder eine Aktion mit dem ComposeTestRule aufrufen, wird der Test vorher synchronisiert und wartet, bis der UI-Baum inaktiv ist.

Normalerweise müssen Sie nichts weiter tun. Es gibt jedoch einige Grenzfälle, über die Sie Bescheid wissen sollten.

Bei der Synchronisierung eines Tests wird Ihre Compose-Anwendung mithilfe einer virtuellen Uhr im Zeitplan fortgesetzt. Das bedeutet, dass Compose-Tests nicht in Echtzeit ausgeführt werden und daher so schnell wie möglich bestanden werden können.

Wenn Sie jedoch die Methoden zum Synchronisieren Ihrer Tests nicht verwenden, findet keine Neuzusammensetzung statt und die UI wird pausiert.

@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()
}

Diese Anforderung gilt nur für Compose-Hierarchien und nicht für den Rest der Anwendung.

Automatische Synchronisierung deaktivieren

Wenn Sie eine Assertion oder Aktion über ComposeTestRule wie assertExists() aufrufen, wird der Test mit der Erstellungs-UI synchronisiert. In manchen Fällen möchten Sie diese Synchronisierung vielleicht stoppen und die Uhr selbst steuern. Beispielsweise können Sie die Zeit für genaue Screenshots einer Animation an einem Punkt steuern, an dem die UI noch ausgelastet ist. Um die automatische Synchronisierung zu deaktivieren, setzen Sie das Attribut autoAdvance in mainClock auf false:

composeTestRule.mainClock.autoAdvance = false

In der Regel verlängern Sie die Zeit dann selbst. Mit advanceTimeByFrame() können Sie genau einen Frame oder mit advanceTimeBy() um eine bestimmte Dauer fortfahren:

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

Inaktive Ressourcen

Compose kann Tests und die UI synchronisieren, sodass jede Aktion und Assertion im Ruhezustand ausgeführt werden und die Uhr nach Bedarf warten oder weiterlaufen kann. Einige asynchrone Vorgänge, deren Ergebnisse den UI-Status beeinflussen, können im Hintergrund ausgeführt werden, während sie beim Test nicht erkannt werden.

Erstellen und registrieren Sie diese inaktiven Ressourcen in Ihrem Test, damit sie bei der Entscheidung, ob die zu testende App ausgelastet oder inaktiv ist, berücksichtigt werden. Sie müssen nichts unternehmen, es sei denn, Sie müssen zusätzliche inaktive Ressourcen registrieren, z. B. wenn Sie einen Hintergrundjob ausführen, der nicht mit Espresso oder Composer synchronisiert ist.

Diese API ist der Inaktiven Ressourcen von Espresso sehr ähnlich, um anzugeben, ob das zu testende Subjekt inaktiv oder ausgelastet ist. Mit der Testregel „Compose“ kannst du die Implementierung von IdlingResource registrieren.

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

Manuelle Synchronisierung

In bestimmten Fällen müssen Sie die Benutzeroberfläche zum Schreiben mit anderen Teilen Ihres Tests oder der Anwendung synchronisieren, die Sie testen.

Die Funktion waitForIdle() wartet, bis Compose inaktiv ist. Die Funktion hängt jedoch vom Attribut autoAdvance ab:

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.

In beiden Fällen wartet waitForIdle() auch auf ausstehende Dreh- und Layoutpass.

Sie können die Uhr auch so lange nach vorne stellen, bis eine bestimmte Bedingung mit advanceTimeUntil() erfüllt ist.

composeTestRule.mainClock.advanceTimeUntil(timeoutMs) { condition }

Die angegebene Bedingung sollte den Status prüfen, auf den sich diese Uhr auswirken kann (funktioniert nur im Zustand „Compose“).

Auf Bedingungen warten

Für alle Bedingungen, die von externer Arbeit abhängen, z. B. dem Laden von Daten oder der Messung oder dem Zeichnen von Android (d. h. Messung oder Zeichnung außerhalb von „Compose“), sollte ein allgemeineres Konzept wie waitUntil() verwendet werden:

composeTestRule.waitUntil(timeoutMs) { condition }

Sie können auch einen der waitUntil-Hilfsprogramme verwenden:

composeTestRule.waitUntilAtLeastOneExists(matcher, timeoutMs)

composeTestRule.waitUntilDoesNotExist(matcher, timeoutMs)

composeTestRule.waitUntilExactlyOneExists(matcher, timeoutMs)

composeTestRule.waitUntilNodeCount(matcher, count, timeoutMs)

Weitere Ressourcen

  • Test-Apps unter Android: Die Haupt-Landingpage für Android-Tests bietet einen umfassenderen Überblick über die Grundlagen und Techniken von Tests.
  • Grundlagen des Testens:Weitere Informationen zu den Kernkonzepten des Testens einer Android-App.
  • Lokale Tests:Sie können einige Tests lokal auf Ihrer eigenen Workstation ausführen.
  • Instrumentierte Tests:Es empfiehlt sich, auch instrumentierte Tests durchzuführen. Das sind Tests, die direkt auf dem Gerät ausgeführt werden.
  • Continuous Integration: Mit Continuous Integration können Sie Ihre Tests in Ihre Bereitstellungspipeline einbinden.
  • Testen Sie verschiedene Bildschirmgrößen:Da Nutzer auf vielen Geräten zur Verfügung stehen, sollten Sie Tests für unterschiedliche Bildschirmgrößen durchführen.
  • Espresso: Diese Espresso-Kenntnisse sind zwar für ansichtsbasierte UIs vorgesehen, können aber für einige Aspekte von Compose-Tests hilfreich sein.