Flaky Tests sind automatisierte Tests, die nicht zuverlässig wiederholbar sind: Bei unverändertem Code bestehen sie manchmal und schlagen ein anderes Mal fehl. Das zerstört das Vertrauen in CI-Pipelines (Continuous Integration), weil Entwicklerinnen und Entwickler nicht mehr erkennen können, ob ein Fehlschlag auf einen echten Defekt hinweist. Die beiden häufigsten Ursachen sind konkurrierende Zugriffe auf gemeinsam genutzte Daten und veränderlicher, gemeinsam genutzter Zustand.
Das Wichtigste in Kürze
- Ein Flaky Test verletzt die grundlegende Eigenschaft der Wiederholbarkeit. Sobald Entwicklerinnen und Entwickler den CI-Ergebnissen nicht mehr vertrauen, bricht der Nutzen von Continuous Integration zusammen.
- Flaky Tests machen mitunter echte Produktionsrisiken sichtbar: vorübergehende Netzwerkfehler, nicht verfügbare Abhängigkeiten und Race Conditions im Test sind dieselben Probleme, auf die später auch Nutzerinnen und Nutzer treffen können.
- Einen Flaky Test aus den regulären CI-Läufen zu nehmen, ist notwendig, reicht aber nicht aus. Die Verantwortung muss einer namentlich benannten Person übertragen werden, nicht nur einem Team.
- Meta lässt jeden neuen Test vor der Aufnahme in die CI über Nacht hundertmal parallel laufen. Diese automatisierte Eingangskontrolle verhindert, dass Flaky Tests überhaupt in den Build gelangen.
- Einen Flaky Test zu löschen, kann eine legitime Lösung sein – besonders dann, wenn kleinere Tests dasselbe Risiko bereits abdecken. Änderungen schnell und sicher auszuliefern ist wichtiger, als Testcode um jeden Preis zu erhalten.
Was einen Test flaky macht
Ein Flaky Test verletzt die Regel der Wiederholbarkeit. Wenn du ihn immer wieder ausführst, sollte er stets dasselbe Ergebnis liefern: bestanden oder fehlgeschlagen, aber immer gleich. Ein Flaky Test tut das nicht. Er besteht, schlägt fehl, besteht erneut und schlägt später wieder fehl. Genau diese Unbeständigkeit ist das Problem.
Gute Tests haben einige Eigenschaften gemeinsam. Sie prüfen ihr Ergebnis selbst, sodass kein Mensch es bestätigen muss. Sie sind schnell, weil Feedback zügig zurückkommen soll. Sie sind isoliert, damit sie parallel laufen können, ohne sich gegenseitig zu beeinflussen. Und sie sind wiederholbar. Flakiness greift genau diese letzte Eigenschaft an.
Der Schaden zeigt sich in deinem Continuous-Integration-System. Du richtest CI ein, um zu prüfen, ob eine Änderung sicher ist. Ist der Build grün, bestätigen alle automatisierten Prüfungen die Änderung so weit wie möglich. Ein Flaky Test vergiftet dieses Signal. Du weißt nicht mehr, ob Rot einen echten Fehlschlag oder bloßes Rauschen bedeutet.
Warum Flaky Tests nicht nur Zeit, sondern Vertrauen kosten
Der tiefere Preis eines Flaky Tests ist der Verlust des Vertrauens in die CI-Pipeline. Alles, was kein konsistentes Signal liefert – egal ob bestanden oder fehlgeschlagen –, untergräbt dieses Vertrauen. Sobald du dem Build nicht mehr glaubst, kannst du ihn dir beinahe sparen.
Auch der Zeitverlust ist real. Die meisten Teams kennen das Ritual: Der Build wird rot, jemand zuckt mit den Schultern und sagt: „Ach ja, das macht er manchmal“, und startet ihn erneut. Manchmal läuft er durch, manchmal nicht. Erst beim zweiten oder dritten Versuch fragt sich jemand, ob doch ein echter Fehler vorliegt. Bis dahin ist die Feedbackschleife länger geworden und ein Teil des Nutzens von CI bereits verloren.
Schnelles Feedback zu einer Änderung ist eines der zentralen Ziele der Softwareentwicklung. Flaky Tests arbeiten diesem Ziel direkt entgegen.
Ein Flaky Test kann nützlich sein
Flakiness bedeutet nicht automatisch, dass der Test schlecht ist. Manchmal weist er auf etwas hin, das du wissen solltest. Wenn der Test besteht, zeigt er dir, dass der Code unter passenden Bedingungen funktioniert. Wenn er fehlschlägt, kann er eine echte Schwäche im System sichtbar machen.
Die Ursache liegt selten im Testframework selbst. Häufiger sind es ein vorübergehender Netzwerkfehler, eine kurzzeitig nicht erreichbare Abhängigkeit, eine nicht verfügbare Datenbank oder Message Queue oder eine Race Condition. Genau mit solchen Bedingungen wird auch dein produktiver Code konfrontiert, sobald Nutzerinnen und Nutzer mit ihm arbeiten.
Ein Flaky Test kann deshalb ein hilfreicher Hinweis sein. Er zwingt dich zu fragen, warum der Test fehlschlägt und ob dein Code robust genug ist, dieselbe Situation in Produktion zu überstehen. Von Abhängigkeiten kannst du keine hundertprozentige Verfügbarkeit erwarten. Bringt ein vorübergehender Ausfall deinen Test zu Fall, kann derselbe Ausfall auch deine Nutzerinnen und Nutzer treffen.
Der übliche Reflex führt in die falsche Richtung. Entwicklerinnen und Entwickler finden einen Flaky Test und geben dem Test oder der Infrastruktur die Schuld: „Das hätte einfach funktionieren müssen.“ Oft lautet die ehrlichere Antwort, dass der Code mit der Störung hätte umgehen müssen – es aber nicht getan hat.
Warum Flaky Tests schwer zu beheben sind
Die Ursache für Flakiness aufzuspüren, kostet Zeit. Deshalb wird die Aufgabe gern aufgeschoben. Ein zuverlässig reproduzierbarer Fehlschlag lässt sich wesentlich leichter debuggen als einer, der nur bei jedem zwanzigsten Lauf auftritt. Zeigt sich das Symptom kaum, zieht sich die Untersuchung in die Länge.
Zwei Ursachen dominieren. Die erste ist der konkurrierende Zugriff auf gemeinsam genutzten, veränderlichen Zustand. In Java lebt beispielsweise ein statischer Wert während der gesamten Laufzeit der JVM. Ein Test verändert ihn, ein späterer Test liest oder verändert ihn erneut – und in dieser Reihenfolge funktioniert alles. Ändert sich die Ausführungsreihenfolge, treten scheinbar aus dem Nichts Fehlschläge auf.
Die zweite Ursache ist das Verändern eines gemeinsam genutzten Zustands, etwa in einer Datenbank. Löscht die erste Zeile deines Tests eine ganze Tabelle, während ein anderer Test gerade dieselbe Tabelle bearbeitet, ist das Chaos vorprogrammiert. Ein verlässliches Indiz für beide Muster: Der Test besteht isoliert, schlägt aber fehl, wenn er gemeinsam mit anderen läuft.
Race Conditions sind besonders schwer aufzuspüren. Simon Stewart schrieb einmal eine eigene ZIP-Komprimierung in Java. Der Test bestand, schlug zweimal fehl und bestand danach wieder, obwohl der Code solide aussah. Ursache war die Genauigkeit der Zeitstempel: Das ZIP-Format speichert sie in Zwei-Sekunden-Schritten. Startete der Test in einer geraden Sekunde, bestand er; in einer ungeraden schlug er fehl. Das Normalisieren der Zeitstempel machte den Test stabil – die Suche nach der Ursache war dennoch mühsam.
So gehst du Schritt für Schritt mit einem Flaky Test um
Als Erstes nimmst du den Test aus der CI. Deine CI muss ein aussagekräftiges Signal liefern, deshalb darf der Flaky Test vorerst nicht in den regulären Läufen bleiben. Danach sorgt ein klarer Ablauf dafür, dass er nicht in Vergessenheit gerät.
Es gibt zwei gängige Wege. Der einfachste ist eine Skip- oder Ignore-Annotation, wie sie die meisten Testframeworks anbieten. Verknüpfe sie mit einem Eintrag im Bugtracker, damit der Test nachvollziehbar bleibt. Alternativ führst du im Repository oder an einer zentralen Stelle eine Ausschlussliste mit den Tests, die beim jeweiligen Lauf übersprungen werden.
Das Selenium-Projekt speist eine solche Datei mit übersprungenen Tests in die CI ein. Eine zentrale Datei ist besser als verstreute Annotationen, die schwer zu finden und leicht zu vergessen sind. An einem gemeinsamen Ort kannst du jederzeit nachvollziehen, welche Tests ausgesetzt wurden.
| Schritt | Was du tust | Warum es wichtig ist |
|---|---|---|
| Entfernen | Den Test per Annotation oder Ausschlussliste aus der CI nehmen | Schützt die Aussagekraft des CI-Signals |
| Nachverfolgen | Mit einem Bug verknüpfen oder zentral in einer Datei erfassen | Hält den Test sichtbar und wiederauffindbar |
| Verantworten | Einer namentlich benannten Person zuweisen | Verhindert, dass sich niemand zuständig fühlt |
| Lösen | Debuggen, verkleinern, wiederholen oder löschen | Stellt ein verlässliches Signal wieder her oder entfernt Ballast |
Viele Unternehmen hören auf, sobald der Test entfernt wurde. Der Build ist wieder stabil, also scheint das Problem gelöst. Ohne eine klar verantwortliche Person passiert danach jedoch meist nichts.
Weise jeden Flaky Test einer Person zu, nicht einem Team
Die Verantwortung für einen Flaky Test gehört zu einer einzelnen Person, nicht abstrakt zu einem Team. Übergibst du ihn nur an ein Team, entsteht ein Allmendeproblem: Alle gehen davon aus, dass sich jemand anderes darum kümmern wird.
Verantwortung bedeutet nicht, sämtliche Arbeiten selbst auszuführen. Die Person stellt sicher, dass geklärt wird, wie der Test behoben wird. Vielleicht delegiert sie einzelne Aufgaben weiter. Vielleicht behandelt sie den Fall wie jeden anderen eingehenden Bug. Entscheidend ist, dass eine namentlich benannte Person ihn voranbringt.
Sobald der Test eine verantwortliche Person hat, wird er bearbeitet. Führe ihn wiederholt aus und grenze die Ursache ein. Finde heraus, warum er flaky ist, und schreibe dann den kleinstmöglichen Test, der belegt, dass deine Korrektur funktioniert. Wenn du konsequent so vorgehst, bewegst du dich in Richtung der klassischen Testpyramide: viele kleine Tests an der Basis, wenige große an der Spitze.
Einen Test zu löschen ist eine legitime Lösung
Du kannst einen Flaky Test auch löschen. Solange du eine Versionsverwaltung verwendest, ist Löschen keine endgültige Vernichtung. Erweist sich der Test später doch als wertvoll, kannst du ihn zurückholen.
Menschen wehren sich oft dagegen, weil der Test „einen wichtigen Ablauf abdeckt“. Dieses Argument wirkt in beide Richtungen. Ist der Ablauf wirklich entscheidend, lohnt sich die Entwicklungszeit, um den Test stabil zu machen. Ist er diese Zeit nicht wert, ist der Test vermutlich auch nicht erhaltenswert. Je wichtiger er angeblich ist, desto höher sollte seine Priorität für eine nachhaltige Korrektur sein.
Manche Teams geben einem Flaky Test eine begrenzte Lebensdauer. Wird er nicht vor Ablauf der Frist behoben, löschen sie ihn als toten Code. Er liefert keinen Nutzen und verursacht Aufwand – seine Entfernung ist dann vertretbar.
Mehrschichtige Teststrategien liefern einen weiteren Grund zum Löschen. Wenn frühere, kleinere Tests das Risiko bereits abdecken, das ein großer Test absichern sollte, ist der große Test redundant. Flakiness tritt besonders häufig in großen Tests auf. Einen solchen Test zu entfernen, dessen Abdeckung bereits anderswo vorhanden ist, kann deshalb ein klarer Gewinn sein.
Wann Wiederholungen vertretbar sind – und wann sie zu teuer werden
Einen Test im selben Build erneut auszuführen, ist ein vertretbarer Kompromiss, aber keine Ideallösung. Hat ein Test eine fünfprozentige Wahrscheinlichkeit für einen flakinessbedingten Fehlschlag, sinkt die kombinierte Wahrscheinlichkeit bei einem zweiten Lauf auf fünf Prozent von fünf Prozent. Mit jedem Retry wird ein falsches Rot deutlich unwahrscheinlicher.
Der Preis ist die Build-Zeit. Ein Flaky Test ist häufig groß, weil er besonders viele bewegliche Teile besitzt. Wiederholst du einen vier Minuten langen Test fünfmal, sprengst du schnell dein Zeitbudget für das Feedback.
Im Durchschnitt sind etwa drei Retries praktikabel, doch entscheidend ist dein eigenes Service Level Objective. Sollen CI-Ergebnisse innerhalb von zehn Minuten vorliegen und dauert ein durchschnittlicher Test drei Minuten, sind drei Läufe möglich, vier jedoch nicht. Du musst Vertrauen und Feedbackgeschwindigkeit gegeneinander abwägen.
So verhinderst du Flaky Tests, bevor sie in den Build gelangen
Eine Eingangskontrolle hält Flakiness von vornherein aus dem Build. Lass einen Flaky Test gar nicht erst zu einem regulären CI-Test werden.
Meta setzt dieses Prinzip im großen Maßstab um. Bevor ein Test die CI beeinflussen darf, läuft er über Nacht hundertmal parallel zu allen anderen Tests. Nur wenn er vollständig stabil bleibt, wird er in die regulären CI-Läufe aufgenommen. Der gesamte Prozess ist automatisiert – manuell wäre dieser Aufwand nicht zu bewältigen.
Du brauchst nicht Metas Ressourcen, um die Idee zu übernehmen. Führe einen neuen Test beispielsweise zehnmal lokal aus und achte auf Instabilität. Dafür musst du festhalten, welche Tests bereits bekannt sind; selbst eine einfache Umbenennung kann einen neuen Prüflauf auslösen. Das ist vertretbar: Ein stabiler Test besteht die Eingangskontrolle, ein Flaky Test hätte gar nicht erst aufgenommen werden sollen.
Die zweite vorbeugende Gewohnheit besteht darin, bekannte Flaky Tests regelmäßig erneut auszuführen. Manchmal wird eine systemische Ursache an anderer Stelle behoben und eine ganze Gruppe von Tests läuft plötzlich wieder stabil. Eine zentrale Datei mit ausgesetzten Tests erleichtert diese Prüfung: Eine Zeile aus einer Liste zu entfernen ist einfacher, als im Code nach verstreuten Annotationen zu suchen. Sobald sich die Tests als stabil erweisen, kehren sie in die regulären CI-Läufe zurück und liefern wieder ein verlässliches Signal.
Wo KI bei Flaky Tests hilft – und wo nicht
KI ist beim Debugging hilfreich, nicht als alleinige Autorin deiner Tests. Sie kann komplexen Code analysieren und beispielsweise darauf hinweisen, dass ein Wert nie gesetzt wird oder eine bestimmte Zeile wahrscheinlich die Ursache enthält. Bei der Suche nach dem Grund für einen flakinessbedingten Fehlschlag kann das wertvoll sein.
Das Risiko ist falsche Sicherheit.
Es ist wie bei einem Betrunkenen in einer Bar, der eine Meinung sehr nachdrücklich vertritt – und damit durchaus falschliegen kann. Simon Stewart
Behandle deshalb jede KI-Antwort als Vorschlag, den ein Mensch prüft. Du kannst zusätzlich ein zweites Modell bitten, die Diagnose des ersten zu überprüfen. Stimmen beide darin überein, dass eine bestimmte Zeile den Fehlschlag erklärt, hast du einen sinnvollen Ausgangspunkt für die Untersuchung.
KI kann viele plausible Testfälle erzeugen. Simon Stewart zieht es jedoch vor, die Bedingungen selbst festzulegen, statt diese Entscheidung vollständig abzugeben. Die passende Einordnung lautet: KI ist ein leistungsfähiges Werkzeug für deine Arbeit, kein Ersatz für sie. Das übergeordnete Ziel bleibt dasselbe: eine sichere Änderung so schnell wie möglich zu den Nutzerinnen und Nutzern zu bringen. Je weniger unnötigen Code du dabei mitführst, desto besser.


