Android Coden
Android 4 min lesen

Compose UI Testing

Compose UI Testing prüft Screens über den Semantik-Baum statt über Implementierungsdetails. Du lernst Finder, Matcher und Assertions gezielt einzusetzen.

Wenn du Compose-Screens testen willst, stehst du vor einer grundsätzlichen Frage: Testest du, wie dein Code intern aufgebaut ist – oder testest du, was der Nutzer tatsächlich sieht und bedienen kann? Compose UI Testing beantwortet diese Frage eindeutig: Tests greifen über den Semantik-Baum auf UI-Elemente zu, nie über interne Implementierungsdetails. Das Ergebnis sind Tests, die Refactorings überleben, weniger brüchig sind und echtes Nutzerverhalten widerspiegeln.

Was ist das?

Compose UI Testing ist das offizielle Test-Framework für Jetpack Compose und Teil der AndroidX-Test-Bibliotheken. Im Mittelpunkt steht der Semantik-Baum: Compose baut parallel zum Layout-Baum einen zweiten Baum auf, der ausschließlich die semantisch relevanten Informationen enthält – also das, was Screenreader und automatisierte Tests sehen sollen. Jeder Node (Knoten) in diesem Baum entspricht einem Composable, das Semantik-Properties gesetzt hat, etwa contentDescription, testTag oder text.

Der entscheidende Unterschied zu klassischen View-basierten Tests mit Espresso: Du referenzierst Elemente nie über View-IDs oder Klassen-Namen. Stattdessen nutzt du semantische Eigenschaften, die beschreiben, was ein Element für den Nutzer bedeutet. Ein umbenannter Composable oder eine verschobene Hierarchie zerstört keinen Test, solange die Semantik unverändert bleibt. Das macht die Test-Suite erheblich wartungsärmer.

Im Kontext der Android-Qualitätsstrategie ergänzt Compose UI Testing die Unit-Tests auf ViewModel-Ebene: Während Unit-Tests die Logik isoliert prüfen, verifizieren UI-Tests das Zusammenspiel zwischen State und Darstellung so, wie der Nutzer es erlebt.

Wie funktioniert es?

Das Framework dreht sich um drei Konzepte: Finder, Matcher und Assertions.

Finder und Matcher

Der Einstiegspunkt ist die ComposeTestRule, die du per Regel in deinen Test einbindest. Mit composeTestRule.onNode(matcher) oder onAllNodes(matcher) wählst du einen oder mehrere Nodes aus dem Semantik-Baum aus. Als Matcher nutzt du vorgefertigte Funktionen aus dem androidx.compose.ui.test-Paket:

  • hasText("Senden") – findet Nodes mit diesem sichtbaren Text
  • hasContentDescription("Schließen") – findet Nodes mit dieser Accessibility-Beschreibung
  • hasTestTag("submit-button") – findet Nodes mit dem gesetzten Test-Tag
  • isEnabled() / isFocused() – prüft den semantischen Zustand

Matcher lassen sich mit and und or kombinieren: hasText("Senden") and isEnabled() findet genau den aktivierten Senden-Button und keinen deaktivierten mit demselben Text.

Assertions und Actions

Auf dem gefundenen Node rufst du Assertions auf, um den aktuellen Zustand zu prüfen:

  • assertIsDisplayed() – ist der Node im sichtbaren Bereich?
  • assertIsEnabled() / assertIsNotEnabled()
  • assertTextEquals("...") – hat der Node exakt diesen Text?
  • assertContentDescriptionEquals("...")

Für Interaktionen stehen Actions bereit: performClick(), performTextInput("..."), performScrollTo() oder performImeAction(). Actions verändern den State und erlauben dir, danach wieder Assertions auszuführen.

In der Praxis

Ein typischer Test für einen Login-Screen, der den Button erst aktiviert, wenn beide Felder befüllt sind:

@get:Rule
val composeTestRule = createComposeRule()

@Test
fun loginButton_istDeaktiviert_wennFelderLeer() {
    composeTestRule.setContent {
        LoginScreen(onLogin = {})
    }

    composeTestRule
        .onNode(hasText("Anmelden"))
        .assertIsNotEnabled()
}

@Test
fun loginButton_wirdAktiviert_nachEingabe() {
    composeTestRule.setContent {
        LoginScreen(onLogin = {})
    }

    composeTestRule
        .onNode(hasTestTag("email-field"))
        .performTextInput("[email protected]")

    composeTestRule
        .onNode(hasTestTag("password-field"))
        .performTextInput("geheim123")

    composeTestRule
        .onNode(hasText("Anmelden"))
        .assertIsEnabled()
}

Häufige Stolperfalle: fehlende Semantik

Der häufigste Fehler beim Einstieg ist, dass ein Node nicht gefunden wird, weil das Composable keine Semantik-Properties trägt. Box, Column oder Row ohne Modifier.semantics { } oder Modifier.testTag(...) sind im Semantik-Baum schlicht unsichtbar. Wenn onNode(hasTestTag("my-box")) mit einer AssertionError-Meldung fehlschlägt, prüfe als erstes, ob das Tag auch wirklich gesetzt ist:

Box(modifier = Modifier.testTag("my-box")) {
    // Inhalt
}

Ein weiterer Fallstrick betrifft das useUnmergedTree-Flag. Standardmäßig liefert Compose einen zusammengeführten Semantik-Baum, in dem Kinder-Semantik nach oben propagiert wird. Bei zusammengesetzten Komponenten – etwa einem Button, der intern einen Text-Composable enthält – kann der Text-Node im zusammengeführten Baum am Button-Node erscheinen. In seltenen Fällen musst du onNode(matcher, useUnmergedTree = true) nutzen, um gezielt an den ursprünglichen, ungemergten Node zu gelangen. Starte immer mit dem Standard (merged), und wechsle nur dann auf useUnmergedTree, wenn ein Test unerwartet fehlschlägt und der Layout Inspector zeigt, dass die Semantik korrekt gesetzt ist.

Fazit

Compose UI Testing verlagert den Fokus vom Implementierungsdetail auf das Nutzererlebnis: Deine Tests beschreiben, was auf dem Bildschirm zu sehen ist und was der Nutzer tun kann – nicht, wie der Code dahinter strukturiert ist. Das macht die Test-Suite langlebiger und wartbarer, weil interne Umbauten keine kaskadierenden Testfehler verursachen. Um dein Verständnis zu festigen, öffne einen bestehenden Compose-Screen, aktiviere im Android Studio Layout Inspector den Semantik-Baum und vergleiche, welche Nodes tatsächlich sichtbar sind. Schreibe dann mindestens zwei Tests: einen positiven, der einen sichtbaren und aktivierten Zustand bestätigt, und einen negativen, der auf eine ungültige Eingabe korrekt reagiert. Dieser kleine Übungs-Zyklus macht den Unterschied zwischen theoretischem Wissen und echtem, produktionstauglichem Test-Knowhow.

Quellen (4)
Redaktion

Geschrieben von

Redaktion

Das Redaktionsteam recherchiert und schreibt Artikel zu aktuellen Themen rund um Tech, Lifestyle und Ratgeber.