Tests synchronisieren

Compose-Tests werden standardmäßig mit Ihrer Benutzeroberfläche synchronisiert. Wenn Sie eine Bestätigung oder eine Aktion mit der ComposeTestRule aufrufen, wird der Test vorab synchronisiert und wartet, bis der UI-Baum inaktiv ist.

Normalerweise müssen Sie nichts unternehmen. Es gibt jedoch einige Grenzfälle, die Sie kennen sollten.

Wenn ein Test synchronisiert wird, wird Ihre Compose-App mithilfe einer virtuellen Uhr in der Zeit vorangestellt. Das bedeutet, dass Compose-Tests nicht in Echtzeit ausgeführt werden, damit sie so schnell wie möglich bestanden werden können.

Wenn Sie die Methoden zum Synchronisieren Ihrer Tests jedoch nicht verwenden, erfolgt keine Neuzusammensetzung und die UI wird als pausiert angezeigt.

@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 Bestätigung oder Aktion über die ComposeTestRule aufrufen, z. B. assertExists(), wird der Test mit der Compose-Benutzeroberfläche synchronisiert. In einigen Fällen möchten Sie diese Synchronisierung möglicherweise beenden und die Uhr selbst steuern. So können Sie beispielsweise die Zeit steuern, um genaue Screenshots einer Animation zu einem Zeitpunkt aufzunehmen, an dem die Benutzeroberfläche noch aktiv ist. Wenn Sie die automatische Synchronisierung deaktivieren möchten, legen Sie die Eigenschaft autoAdvance in mainClock auf false fest:

composeTestRule.mainClock.autoAdvance = false

In der Regel setzen Sie die Zeit dann selbst fort. Mit advanceTimeByFrame() kannst du genau einen Frame vor- und mit advanceTimeBy() um eine bestimmte Dauer vorspulen:

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

Inaktive Ressourcen

Mit Compose können Tests und die UI synchronisiert werden, sodass jede Aktion und Assertion im inaktiven Zustand ausgeführt wird, entweder im Wartezustand oder im Bedarfsfall. Einige asynchrone Vorgänge, deren Ergebnisse sich auf den UI-Status auswirken, können jedoch im Hintergrund ausgeführt werden, ohne dass sie im Test berücksichtigt werden.

Erstellen und registrieren Sie diese Inaktivitätsressourcen in Ihrem Test, damit sie bei der Entscheidung berücksichtigt werden, ob die getestete App aktiv oder inaktiv ist. 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 Compose synchronisiert ist.

Diese API ähnelt den Inaktivitätsressourcen von Espresso, die angeben, ob das Testobjekt inaktiv oder aktiv ist. Verwenden Sie die Testregel „Compose“, um die Implementierung der IdlingResource zu registrieren.

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

Manuelle Synchronisierung

In bestimmten Fällen müssen Sie die Compose-UI mit anderen Teilen des Tests oder der zu testenden Anwendung synchronisieren.

Die Funktion waitForIdle() wartet, bis das Tool „Compose“ inaktiv ist, hängt aber von der Eigenschaft 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.

Beachten Sie, dass in beiden Fällen auch auf ausstehende Draw- und Layout-Passe gewartet wird.waitForIdle()

Mit advanceTimeUntil() können Sie die Zeit auch vorspulen, bis eine bestimmte Bedingung erfüllt ist.

composeTestRule.mainClock.advanceTimeUntil(timeoutMs) { condition }

Die angegebene Bedingung sollte den Status prüfen, der von dieser Uhr beeinflusst werden kann. Sie funktioniert nur mit dem Status „Compose“ (Komponieren).

Auf Bedingungen warten

Für alle Bedingungen, die von externen Vorgängen abhängen, z. B. das Laden von Daten oder das Messen oder Zeichnen von Android (d. h. außerhalb von Compose), sollte ein allgemeineres Konzept wie waitUntil() verwendet werden:

composeTestRule.waitUntil(timeoutMs) { condition }

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

composeTestRule.waitUntilAtLeastOneExists(matcher, timeoutMs)

composeTestRule.waitUntilDoesNotExist(matcher, timeoutMs)

composeTestRule.waitUntilExactlyOneExists(matcher, timeoutMs)

composeTestRule.waitUntilNodeCount(matcher, count, timeoutMs)

Zusätzliche Ressourcen

  • Apps unter Android testen: Die Haupt-Landingpage für Android-Tests bietet einen umfassenderen Überblick über die Grundlagen und Testverfahren.
  • Grundlagen des Testens: Hier erfahren Sie mehr über die grundlegenden Konzepte beim Testen einer Android-App.
  • Lokale Tests: Einige Tests können Sie lokal auf Ihrer eigenen Workstation ausführen.
  • Instrumentierte Tests:Es empfiehlt sich, auch instrumentierte Tests auszufü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.
  • Unterschiedliche Bildschirmgrößen testen: Da Nutzern eine Vielzahl von Geräten zur Verfügung steht, sollten Sie verschiedene Bildschirmgrößen testen.
  • Espresso: Obwohl Espresso für viewbasierte UIs gedacht ist, können Kenntnisse zu Espresso auch für einige Aspekte von Compose-Tests hilfreich sein.