Anleitungen

Alternativen zu Idling Resources in Compose-Tests: die waitUntil-APIs (aktualisiert)

Lesezeit: 3 Minuten
Jose Alcérreca
Developer Relations Engineer

In diesem Artikel erfahren Sie, wie Sie die waitUntil-Test-API in Compose verwenden, um zu warten, bis bestimmte Bedingungen erfüllt sind. In manchen Situationen ist das eine gute Alternative zur Verwendung von Idling Resources.

[Aktualisierung 2023] Kurz gesagt: Verwenden Sie die neuen waitUntil-APIs, um Compose-Tests (ab Version 1.4.0) zu synchronisieren.


Was ist Synchronisierung?

Eine Möglichkeit, Tests zu kategorisieren, ist ihr Umfang. Kleine Tests oder Einheitentests konzentrieren sich auf kleine Teile Ihrer App, während große Tests oder End-to-End-Tests einen großen Teil Ihrer App abdecken. Weitere Informationen zu dieser und anderen Arten von Tests finden Sie in der neu aktualisierten Testdokumentation.

Eingabetaste drücken oder klicken, um das Bild in Originalgröße anzusehen

large_0_9n_Nqkt_HHUTOQ_In_AI_b113b43bcf.png
Verschiedene Testbereiche in einer App

Die Synchronisierung ist der Mechanismus, mit dem der Test weiß, wann der nächste Vorgang ausgeführt werden soll. Je größer der Codeabschnitt ist, den Sie überprüfen möchten, desto schwieriger ist es, ihn mit dem Test zu synchronisieren. In Einheitentests lässt sich die Ausführung des zu prüfenden Codes ganz einfach steuern. Wenn wir jedoch den Umfang auf weitere Klassen, Module und Ebenen ausweiten, wird es für das Testframework schwierig zu erkennen, ob die App gerade einen Vorgang ausführt oder nicht.

Eingabetaste drücken oder klicken, um das Bild in Originalgröße anzusehen

large_correct_b1a355f41b.webp
Korrekte Synchronisierung zwischen Test und App

androidx.test und damit auch Compose Test verwenden einige Tricks im Hintergrund, sodass Sie sich nicht zu viele Gedanken darüber machen müssen. Wenn der Hauptthread beispielsweise ausgelastet ist, wird der Test angehalten, bis die nächste Zeile ausgeführt werden kann.

Sie können jedoch nicht alles wissen. Wenn Sie beispielsweise Daten in einem Hintergrundthread laden, führt das Testframework möglicherweise den nächsten Vorgang zu früh aus, sodass der Test fehlschlägt. Am schlimmsten ist es, wenn dies nur in einem kleinen Prozentsatz der Fälle passiert, was den Test unzuverlässig macht.

Option 1: Ressourcen im Leerlauf

Idling Resources sind eine Espresso-Funktion, mit der Sie als Entwickler festlegen können, wann die App beschäftigt ist. Sie haben zwei Möglichkeiten, sie zu verwenden:

1. Sie werden in dem Framework oder der Bibliothek installiert, die Aufgaben ausführt, die im Test nicht sichtbar sind.

Ein gutes Beispiel dafür ist RxIdler, das einen RxJava-Scheduler umschließt. Dies ist die bevorzugte Methode zum Registrieren von Idling Resources, da Sie so die Testeinrichtung sauber vom Testcode trennen können.

2. Sie ändern den zu testenden Code so, dass explizit Informationen dazu bereitgestellt werden, ob Ihre App gerade beschäftigt ist.

Sie können beispielsweise Ihr Repository (oder ein Test-Double) so ändern, dass es angibt, dass es beim Laden von Daten aus einer Datenquelle beschäftigt ist:

Das ist nicht ideal, da Sie Ihren Produktionscode verunreinigen oder komplizierte Test-Doubles erstellen. Außerdem gibt es Situationen, in denen sie schwer zu installieren sind. Wie würden Sie beispielsweise Idling Resources in einem Kotlin-Flow verwenden? Welches Update ist das letzte?

Stattdessen können wir warten.

Option 2: Falsches Warten

Das Laden von Daten ist in der Regel schnell, insbesondere bei Verwendung von gefälschten Daten. Warum also Zeit mit inaktiven Ressourcen verschwenden, wenn Sie den Test einfach für einige Sekunden in den Ruhezustand versetzen können?

Dieser Test wird entweder langsamer als erforderlich ausgeführt oder schlägt fehl. Wenn Sie Hunderte oder Tausende von UI-Tests haben, sollten diese so schnell wie möglich ausgeführt werden.

Außerdem kann es vorkommen, dass Emulatoren oder Geräte sich nicht richtig verhalten und ruckeln, sodass der Vorgang etwas länger als 2.000 ms dauert und der Build fehlschlägt. Bei Hunderten von Tests wird das zu einem großen Problem.

0_DOCdjq-JpPDGV5OB.png

Option 3: Richtig warten

Wenn Sie den zu testenden Code nicht ändern möchten, um zu erkennen, wann er beschäftigt ist, können Sie auch warten, bis eine bestimmte Bedingung erfüllt ist, anstatt eine beliebige Zeit lang zu warten.

1_jIYFxE4qlHXMi2SwW6JemA.png

In Compose können Sie die Funktion waitUntil verwenden, die eine weitere Funktion mit einem booleschen Wert als Ergebnis akzeptiert.

Update vom 22.03.2023: Ab Compose 1.4.0 haben wir eine neue Reihe von „waitUntil“-APIs hinzugefügt:

[Vor Version 1.4.0: Verwenden Sie diese Hilfsfunktionen: waitUntilExists, waitUntilNodeCount]

…und so verwenden Sie sie:

Verwenden Sie diese APIs nur, wenn Sie Ihren Test mit der Benutzeroberfläche synchronisieren müssen. Die Synchronisierung bei jeder Testanweisung führt zu einer unnötigen Belastung des Testcodes, was die Wartung erschwert.

Wann sollten Sie sie verwenden? Ein guter Anwendungsfall dafür ist das Laden von Daten aus einem Observable (mit LiveData, Kotlin Flow oder RxJava). Wenn Ihre Benutzeroberfläche mehrere Updates erhalten muss, bevor sie als inaktiv gilt, können Sie die Synchronisierung mit waitUntil vereinfachen.

Wenn Sie beispielsweise einen Flow aus einer Ansicht erfassen:

Sie senden mehrere Elemente an sie:

Wenn es unbestimmte Zeit dauert, bis repository das erste Ergebnis zurückgibt, geht das Test-Framework davon aus, dass „Loading“ der Leerlaufstatus ist (der in collectAsState zugewiesene Anfangswert), und fährt mit der nächsten Anweisung fort.

Sie können den Test also viel zuverlässiger machen, wenn Sie dafür sorgen, dass in der Benutzeroberfläche keine Ladeanzeige zu sehen ist:


Viel Spaß beim Testen!


Lizenz für Code-Snippets:

  Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0
Verfasst von:

Weiterlesen