Tests sinnvoll benennen
Gut benannte Tests zeigen beim Fehlschlag sofort, was falsch läuft. Lerne Konventionen für lesbare und wartbare Testsuiten.
Wenn ein Test in der CI-Pipeline fehlschlägt, ist der Testname die erste Information, die du siehst – noch bevor du eine einzige Zeile Code liest. Ein guter Name entscheidet darüber, ob du in Sekunden verstehst, was schiefgelaufen ist, oder ob du erst den Testbody, die Assertions und den Stack Trace durchforsten musst. Testnamen sind keine Nebensache; sie sind die dokumentierte Absicht hinter jedem Testszenario.
Was ist das?
Testbenennung ist die Disziplin, Testmethoden Namen zu geben, die drei Fragen gleichzeitig beantworten: Was wird getestet? Unter welcher Bedingung? Welches Ergebnis wird erwartet? Diese drei Dimensionen machen einen Testnamen vollständig und eindeutig – und damit nützlich.
In Android-Projekten begegnest du Testnamen in JUnit-Unit-Tests, Espresso-Integrationstests und Compose-UI-Tests. Alle drei erscheinen im Android Studio Test Runner, im Gradle-Build-Output und in CI-Berichten wie GitHub Actions oder Bitrise. Weil Tests oft von Entwicklerinnen und Entwicklern geschrieben werden, die sie später nicht mehr kennen, trägt ein guter Name dazu bei, dass auch Kolleginnen und Kollegen im Code-Review sofort verstehen, welches Verhalten verifiziert wird.
Ein Testname ist außerdem eine Form der lebenden Spezifikation: Er beschreibt das erwartete Verhalten des Systems, nicht ein Implementierungsdetail. Wenn die Implementierung sich ändert, bleibt die Spezifikation im Namen erhalten – solange du ihn korrekt formuliert hast. Das macht Testnamen zu einem der günstigsten Dokumentations-Werkzeuge in deiner Toolbox.
Wie funktioniert es?
Die verbreitetste Konvention im Android-Umfeld ist das given-when-then-Muster, das aus Behavior Driven Development (BDD) stammt:
given<Ausgangszustand>_when<Aktion>_then<ErwartetesErgebnis>
Alternativ wird das should-when-Muster verwendet, das kompakter ist und sich gut für einfache Szenarien eignet:
<MethodeOderKlasse>_should<ErwartetesVerhalten>_when<Bedingung>
Kotlin bietet eine dritte Möglichkeit: Backtick-Bezeichner erlauben Leerzeichen und Sonderzeichen in Methodennamen. Damit lassen sich Testnamen in natürlicher Sprache formulieren, was die Lesbarkeit für gemischte Teams weiter steigert:
@Test
fun `navigates to home screen when login succeeds with valid credentials`() { ... }
JUnit 4 – das Standard-Test-Framework auf Android – zeigt den Methodennamen direkt im Testergebnis an. JUnit 5 erlaubt zusätzlich die @DisplayName-Annotation für einen beschreibenden Label, der unabhängig vom Methodennamen ist. Beide Ansätze sind kompatibel mit dem Android-Test-Runner und gängigen CI-Systemen.
Die Wahl des Musters ist Teamsache. Wichtiger als die konkrete Konvention ist die konsequente Anwendung: Gemischte Stile innerhalb eines Projekts erzeugen mehr Reibung als ein schlechtes Muster, das einheitlich durchgezogen wird. Halte die Entscheidung in einem kurzen Abschnitt in deiner CONTRIBUTING-Datei fest, damit neue Entwickler nicht raten müssen.
In der Praxis
Betrachte dieses Beispiel aus einem ViewModel-Test für einen Login-Flow:
// Schlecht – was genau wird hier getestet?
@Test
fun testLogin() {
val viewModel = LoginViewModel(fakeRepo)
viewModel.login("user", "pass")
assertTrue(viewModel.uiState.value is LoginUiState.Success)
}
// Gut – Absicht und Bedingung sind sofort klar
@Test
fun `givenValidCredentials_whenLogin_thenUiStateIsSuccess`() {
val viewModel = LoginViewModel(fakeRepo)
viewModel.login("validUser", "validPass")
assertTrue(viewModel.uiState.value is LoginUiState.Success)
}
// Alternativ: natürliche Sprache mit Kotlin-Backticks
@Test
fun `ui state becomes Success when login is called with valid credentials`() {
val viewModel = LoginViewModel(fakeRepo)
viewModel.login("validUser", "validPass")
assertTrue(viewModel.uiState.value is LoginUiState.Success)
}
Der schlechte Name testLogin verrät nichts über das Szenario: Testet er den Erfolgsfall? Einen Netzwerkfehler? Die Validierung leerer Felder? Wenn dieser Test in der CI fehlschlägt, musst du den Testbody lesen, bevor du weißt, ob der Fehlschlag überhaupt relevant für das aktuelle Feature ist.
Typische Stolperfalle: Aktionsverben ohne Kontext
Die häufigste Fehlerquelle ist das Präfix test, check oder verify ohne anschließende Beschreibung. Auch scheinbar konkrete Namen wie testLoginWithWrongPassword sind unvollständig, weil das erwartete Ergebnis fehlt: Soll der Test beweisen, dass eine Fehlermeldung erscheint? Dass kein Token gespeichert wird? Dass der Fehler-State korrekt gesetzt wird?
Ergänze daher immer das erwartete Ergebnis im Namen – auch wenn er dadurch länger wird. Lange Testnamen sind keine Schwäche; sie sind Dokumentation. Der Compiler entfernt sie aus dem Release-Build.
Compose-Tests
In Compose-UI-Tests empfiehlt sich dasselbe Muster. Der Name des composeTestRule-Aufrufs ist bereits klar; der Testname sollte das Composable und das erwartete UI-Verhalten benennen:
@Test
fun `login button is disabled when password field is empty`() {
composeTestRule.setContent { LoginScreen(viewModel) }
composeTestRule.onNodeWithTag("passwordField").performTextInput("")
composeTestRule.onNodeWithTag("loginButton").assertIsNotEnabled()
}
Dieser Name kommuniziert beim Fehlschlag sofort: Das Login-Button-Verhalten bei leerem Passwortfeld ist gebrochen – kein weiteres Lesen nötig.
Fazit
Testnamen sind die günstigste Form der Dokumentation, die du schreiben kannst: Sie kosten keine zusätzlichen Zeilen, zahlen sich aber bei jedem CI-Fehlschlag aus. Nimm dir jetzt fünf Minuten, öffne ein bestehendes Testfile in deinem Projekt und suche nach Methoden, deren Namen mit test, check oder verify beginnen, ohne das Szenario zu nennen. Benenne drei davon nach dem given-when-then- oder Backtick-Muster um, führe den Test-Runner aus und beobachte, wie viel verständlicher der Testergebnis-Output wird. Dieser kleine Refactor lohnt sich besonders vor einem Code-Review oder bevor du eine Testsuite an ein neues Teammitglied übergibst.