Compose-Tests werden standardmäßig mit Ihrer Benutzeroberfläche synchronisiert. Wenn Sie eine Assertion oder eine Aktion mit ComposeTestRule
aufrufen, wird der Test vorher synchronisiert und wartet, bis der UI-Baum im Leerlauf ist.
Normalerweise müssen Sie nichts weiter tun. Es gibt jedoch einige Grenzfälle, die Sie kennen sollten.
Wenn ein Test synchronisiert wird, wird die Zeit in Ihrer Compose-App mithilfe einer virtuellen Uhr vorverlegt. Das bedeutet, dass Compose-Tests nicht in Echtzeit ausgeführt werden, damit sie so schnell wie möglich abgeschlossen werden können.
Wenn Sie jedoch nicht die Methoden verwenden, mit denen Ihre Tests synchronisiert werden, erfolgt keine Neuzusammenstellung und die Benutzeroberfläche scheint angehalten zu sein.
@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 App.
Automatische Synchronisierung deaktivieren
Wenn Sie eine Assertion oder Aktion über ComposeTestRule
aufrufen, z. B. assertExists()
, wird Ihr 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 den Zeitpunkt für genaue Screenshots einer Animation festlegen, auch wenn die Benutzeroberfläche noch beschäftigt ist. Wenn Sie die automatische Synchronisierung deaktivieren möchten, legen Sie das Attribut autoAdvance
in der mainClock
auf false
fest:
composeTestRule.mainClock.autoAdvance = false
Normalerweise stellen Sie die Zeit dann selbst vor. Mit advanceTimeByFrame()
können Sie genau einen Frame vorwärts springen und mit advanceTimeBy()
um eine bestimmte Dauer:
composeTestRule.mainClock.advanceTimeByFrame()
composeTestRule.mainClock.advanceTimeBy(milliseconds)
Inaktive Ressourcen
Compose kann Tests und die Benutzeroberfläche synchronisieren, sodass jede Aktion und Assertion in einem inaktiven Zustand ausgeführt wird. Die Uhr wird bei Bedarf angehalten oder weitergestellt. Einige asynchrone Vorgänge, deren Ergebnisse sich auf den UI-Status auswirken, können jedoch im Hintergrund ausgeführt werden, ohne dass der Test davon Kenntnis hat.
Erstellen und registrieren Sie diese Leerlaufressourcen in Ihrem Test, damit sie bei der Entscheidung, ob die zu testende App beschäftigt oder im Leerlauf ist, berücksichtigt werden. Sie müssen nur dann Maßnahmen ergreifen, wenn Sie zusätzliche Leerlaufressourcen registrieren müssen, z. B. wenn Sie einen Hintergrundjob ausführen, der nicht mit Espresso oder Compose synchronisiert wird.
Diese API ähnelt den Idling Resources von Espresso, mit denen angegeben wird, ob das zu testende Element im Leerlauf ist oder beschäftigt. Verwenden Sie die Compose-Testregel, um die Implementierung von IdlingResource
zu registrieren.
composeTestRule.registerIdlingResource(idlingResource)
composeTestRule.unregisterIdlingResource(idlingResource)
Manuelle Synchronisierung
In bestimmten Fällen müssen Sie die Compose-Benutzeroberfläche mit anderen Teilen Ihres Tests oder der App, die Sie testen, synchronisieren.
Die Funktion waitForIdle()
wartet, bis Compose im Leerlauf ist. Die Funktion hängt jedoch 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 bei waitForIdle()
auch auf ausstehende Rendern- und Layoutdurchläufe gewartet wird.
Mit advanceTimeUntil()
können Sie die Uhr auch so lange vorwärts stellen, 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 Compose-Status.
Auf Bedingungen warten
Für alle Bedingungen, die von externen Vorgängen abhängen, z. B. Daten laden oder die Measure- oder Draw-Phase von Android (d. h. Measure oder Draw außerhalb von Compose), sollte ein allgemeineres Konzept wie waitUntil()
verwendet werden:
composeTestRule.waitUntil(timeoutMs) { condition }
Sie können auch einen der waitUntil
-Helfer 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: Auf der Haupt-Landingpage für Android-Tests finden Sie einen umfassenderen Überblick über die Grundlagen und Techniken des Testens.
- Grundlagen des Testens:Hier finden Sie weitere Informationen zu den grundlegenden Konzepten für das Testen einer Android-App.
- Lokale Tests:Einige Tests können lokal auf Ihrer Workstation ausgeführt werden.
- 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.
- Verschiedene Bildschirmgrößen testen:Da Nutzer viele verschiedene Geräte verwenden können, sollten Sie verschiedene Bildschirmgrößen testen.
- Espresso: Obwohl Espresso für ansichtsbasierte UIs gedacht ist, kann es für einige Aspekte von Compose-Tests hilfreich sein.