Flaky Tests: Ursachen und Behebung

In unserem Artikel zur Fehleranalyse ging es unter anderem darum, wie sich ein einzelner Flaky Test von einem echten, reproduzierbaren Fehler unterscheiden lässt. Dieser Beitrag setzt genau dort an und geht in die Tiefe: Welche Ursachen stecken empirisch belegt am häufigsten dahinter? Welche konkreten Gegenmaßnahmen passen zu welcher Ursache? Und wie gehen Teams in der Praxis mit Flaky Tests um, die sich nicht sofort beheben lassen?
Ein Flaky Test liefert bei unverändertem Code und unverändertem Testcode mal ein Grün, mal ein Rot. Ohne erkennbaren Grund. Das macht ihn zu einem der teuersten Probleme in der Testautomatisierung: Ein einzelner instabiler Test kann das Vertrauen in eine ganze Suite untergraben, denn sobald ein Fehlschlag routinemäßig als „wahrscheinlich nur wieder der flaky Test“ abgetan wird, geht auch die Aufmerksamkeit für echte Regressionen verloren.
Warum ein einzelner Flaky Test die ganze Suite gefährdet
Der Softwareentwickler Martin Fowler beschreibt das Grundproblem bereits 2011 in einem bis heute vielzitierten Artikel: Ein automatisierter Test ist nur deshalb wertvoll, weil ein Fehlschlag zuverlässig auf einen echten Fehler hindeutet. Bei einem nicht-deterministischen Test ist das nicht mehr gegeben. Ein Rot kann ein echter Bug sein oder einfach nur Zufall, und ohne weitere Untersuchung lässt sich das nicht unterscheiden.
Sobald ein Team diese Unsicherheit einmal hinnimmt und einen Fehlschlag reflexhaft neu startet, statt ihn zu untersuchen, verliert nicht nur der betroffene Test seinen Wert: Die Disziplin, überhaupt auf ein Rot zu reagieren, erodiert auch bei den übrigen, eigentlich zuverlässigen Tests der Suite. Das Ausmaß ist dabei kein Nischenproblem. Laut Google Testing Blog zeigen rund 16 Prozent aller Tests bei Google irgendeine Form von Flakiness.
Fowlers Rat lautet deshalb, einen erkannten Flaky Test sofort in eine separate Quarantäne-Suite zu verschieben, damit die gesunden Tests aussagekräftig bleiben. Mit der ausdrücklichen Einschränkung, dass er dort nicht liegen bleiben darf, sondern zeitnah untersucht werden muss, etwa über eine feste Obergrenze an gleichzeitig quarantänierten Tests oder eine maximale Verweildauer.
Die häufigsten Ursachen: eine empirische Einordnung
Wie häufig welche Ursache tatsächlich vorkommt, hat eine vielzitierte Studie der University of Illinois an 201 Commits aus 51 Open-Source-Projekten der Apache Software Foundation untersucht, die nachweislich einen Flaky Test behoben haben.
Mit weitem Abstand häufigste Ursache war Async Wait (rund 45 % der eindeutig klassifizierbaren Fälle): Der Test wartet über eine feste Zeitspanne (etwa Thread.sleep(2000)) auf eine asynchrone Antwort, die manchmal (etwa bei Thread-Scheduling- oder Netzwerkverzögerungen) länger braucht als die Wartezeit. Ein von den Studienautor*innen dokumentiertes Beispiel aus HBase: Ein Test wartete exakt zwei Sekunden auf die Rückmeldung eines gestarteten Servers und schlug bei Verzögerung fehl; die Entwickler*innen ersetzten die feste Wartezeit durch einen expliziten Aufruf (cluster.waitOnRegionServer(0)), der so lange blockiert, bis die Rückmeldung tatsächlich vorliegt.
Mit deutlichem Abstand folgen Concurrency (rund 20 %, meist falsche Annahmen über die Ausführungsreihenfolge paralleler Threads) und Test Order Dependency (rund 12 %, ein Test verlässt sich auf einen Zustand, den ein anderer, in bestimmter Reihenfolge zuvor gelaufener Test hinterlassen hat). Kleinere, aber wiederkehrende Anteile entfallen auf Resource Leaks (rund 7 %), Netzwerkabhängigkeiten (rund 6 %) sowie System-Zeit, I/O, Zufallswerte und Fließkomma-Vergleiche (zusammen im niedrigen einstelligen Prozentbereich).
Ein nicht unerheblicher Teil der untersuchten Commits ließ sich dabei keiner Kategorie eindeutig zuordnen. Die Ursachenlandschaft lässt sich in der Praxis selten vollständig in wenige Lehrbuchkategorien pressen.
Gegenmaßnahmen: was zu welcher Ursache passt
Zu den vier häufigsten Ursachen aus dem vorigen Abschnitt lassen sich vergleichsweise klare Gegenmaßnahmen benennen.
Gegen Async Wait hilft vor allem, feste Wartezeiten (bare sleeps) konsequent zu vermeiden: Ein Callback, der bei Fertigstellung informiert, ist ideal; wo das nicht möglich ist, ersetzt Polling mit kurzem Intervall und hohem Timeout die feste Wartezeit. Die Tests werden dadurch im Erfolgsfall schneller und im Grenzfall robuster, weil das Timeout selten erreicht wird, ohne dass unnötig lange gewartet werden muss.
Gegen Concurrency und Test Order Dependency hilft konsequente Isolation: Jeder Test baut seinen Ausgangszustand entweder vollständig neu auf oder räumt zuverlässig hinter sich auf; bei Datenbanktests hat sich der Trick bewährt, den Test in einer Transaktion laufen zu lassen und diese am Ende zurückzurollen, statt manuell aufzuräumen.
Netzwerkabhängige Flakiness lässt sich über Test Doubles entschärfen, die das Verhalten entfernter Systeme kontrolliert nachbilden, ergänzt um separate Contract Tests, die regelmäßig prüfen, ob Double und echtes System noch übereinstimmen. Zeitabhängige Tests sollten nie direkt auf die Systemuhr zugreifen, sondern über einen austauschbaren Zeitgeber, der sich im Test auf einen festen Wert einfrieren lässt.
Und bei Resource Leaks als Ursache hilft es, den zugrunde liegenden Pool testweise auf eine einzige Ressource zu begrenzen und bei Erschöpfung einen Fehler zu werfen. Der erste Test, der danach eine Ressource anfordert, schlägt dann sofort und eindeutig fehl, statt dass ein beliebiger späterer Test scheinbar grundlos rot wird.
Erkennung und Umgang in der Praxis: Quarantäne statt Ignorieren
In großen Suiten reicht manuelle Ursachensuche allein nicht mehr aus. Hier setzt automatisierte Erkennung an. Die gängige Grundtechnik ist, einen verdächtigen Test mehrfach hintereinander laufen zu lassen und bei widersprüchlichen Ergebnissen automatisch zu markieren; CI-Plattformen wie Datadog CI Visibility, Trunk oder BuildPulse bauen darauf automatisierte Retries, eine commit-bezogene Zuordnung („welcher Commit hat diesen Test flaky gemacht“) und eine automatische Quarantäne auf, statt dass Teams Flakiness manuell in Tabellen nachhalten.
Wie wirksam automatisierte Quarantäne sein kann, zeigt ein Erfahrungsbericht von Slack aus dem eigenen Engineering-Blog: Das Mobile-Team deaktivierte in einem als „Project Cornflake“ bezeichneten System automatisiert Tests, die einen Flakiness-Schwellenwert überschritten, eröffnete dazu automatisch ein Ticket und einen Pull Request und benachrichtigte das zuständige Team. Der Test blieb damit sichtbar offen, statt nur lautlos ignoriert zu werden.
Innerhalb weniger Monate stieg die Stabilität des Hauptbranches von rund 20 % auf 96 %, die Fehlschlagsrate der CI-Jobs sank von rund 57 % auf unter 4 %, und den Entwickler*innen wurden nach eigenen Angaben über 550 Stunden manueller Triage-Arbeit erspart.
Der Ansatz ersetzt keine der im vorigen Abschnitt beschriebenen Gegenmaßnahmen. Er verschafft Teams nur die Zeit, sie tatsächlich umzusetzen, statt in einer immer unzuverlässiger werdenden Suite unterzugehen.
Fazit
Flaky Tests sind kein Randproblem, das sich mit einem Rerun-Button erledigen lässt, sondern nach Studienlage zu einem erheblichen Teil auf wenige, gut dokumentierte Ursachen zurückzuführen: allen voran unsauber gehandhabte Asynchronität, gefolgt von Nebenläufigkeit und fehlender Testisolation.
Für jede dieser Ursachen existieren etablierte, konkrete Gegenmaßnahmen, von Polling statt fixer Wartezeiten bis zu Transaktions-Rollbacks für die Testisolation. Wo die Ursache nicht sofort behoben werden kann, ersetzt eine automatisierte Quarantäne das bloße Ignorieren: Der Test bleibt sichtbar und nachverfolgbar, statt die Aussagekraft der gesamten Suite mit nach unten zu ziehen.
Häufen sich in Ihrer Testsuite Fehlschläge, die sich nicht reproduzieren lassen? Wir schauen uns das gerne gemeinsam mit Ihnen an.
Kontaktieren Sie uns unter: office@gruener-it.at
Quellen
Datadog – What Is a Flaky Test? Causes, Identification & Remediation
Google Testing Blog – Flaky Tests at Google and How We Mitigate Them (2016)
Luo, Hariri, Eloussi, Marinov – An Empirical Analysis of Flaky Tests (FSE 2014)
Slack Engineering – Handling Flaky Tests at Scale: Auto Detection & Suppression




Kommentare