Die meisten Teams haben kein Problem mit „mangelnden Tests“. Es gibt ein Problem mit schlecht konzipierten Tests.
Sie fangen gut gemeint an. Jemand schreibt einen Test, dann einen anderen, und innerhalb weniger Monate entsteht eine Suite mit Hunderten von Fällen. Das Problem tritt auf, wenn die Ausführung dieser Suite zwanzig Minuten dauert, aufgrund einer geringfügigen Änderung abbricht und niemand mehr dem roten Ergebnis vertraut. Die natürliche Reaktion besteht darin, den Test „immer fehlschlagen“ auszuschalten. Von da an wird die Suite zum Theater.
Dieser Leitfaden ist unkompliziert: Bevor Sie besprechen, welches Tool Sie verwenden möchten, entscheiden Sie sich für die Architektur Ihrer Tests. Es ist diese Entscheidung, die eine Suite, die das Team schützt, von einer Suite trennt, die es verlangsamt.
Warum Architektur vor Berichterstattung kommt
Die Abdeckung ist eine Kennzahl, die leicht zu messen und leicht zu täuschen ist. Sie können eine Abdeckung von 90 % erreichen, indem Sie Getter und Setter testen, ohne wichtige Geschäftsregeln zu schützen.
Was die Geschwindigkeit wirklich aufrechterhält, ist die Art und Weise, wie die Tests organisiert sind: was jedes Level testet, wie schnell sie laufen, wie isoliert sie sind und wie klar sie darauf hinweisen, was kaputt ist. Dies ist eine architektonische Entscheidung, keine Mengenentscheidung.
Ich betrachte es als Infrastruktur. Sie skalieren ein System nicht durch zufälliges Stapeln von Servern; definiert Ebenen, Verantwortlichkeiten und Verträge. Dasselbe gilt auch für Tests. Ohne Design wächst die Suite als Schulden und nicht als Vermögenswert.
Die Pyramide ist immer noch der Ausgangspunkt
Die Testpyramide bleibt zunächst einmal das nützlichste mentale Modell. Die Basis sind Unit-Tests: viele, schnell, isoliert. In der Mitte Integrationstests, die prüfen, ob die Teile miteinander kommunizieren. An der Spitze stehen einige End-to-End-Tests, die den Benutzerfluss trainieren.
Die Faustregel ist einfach. Je höher die Pyramide, desto teurer und langsamer ist der Test und desto anfälliger ist er. Deshalb muss die Oberseite schmal sein. Ein Team, das die Pyramide umdreht, mit Dutzenden von Schnittstellentests und wenigen Unit-Tests, wird eine langsame und instabile Suite haben.
Der häufigste Fehler besteht darin, die Pyramide als Dogma zu behandeln. Bei Systemen, die sehr auf Integration ausgerichtet sind, beispielsweise APIs, die Dienste orchestrieren, ist es sinnvoll, die Integrationsschicht zu verdicken. Das Format ist weniger wichtig als das Prinzip: Verifizierung auf die günstigste Ebene bringen, die noch Vertrauen schafft.
Entscheidungen, die die Architektur definieren
Einige Entscheidungen wirken sich unverhältnismäßig stark auf den Zustand der Suite aus. Es lohnt sich, sie frühzeitig zu lösen.
Das erste ist, was isoliert werden soll. Unit-Tests müssen ohne Bank, ohne Netzwerk und ohne echte Uhr laufen. Wenn Sie ein halbes System hochfahren müssen, um eine Funktion zu testen, ist das Problem nicht das Testen, sondern die Codekopplung. Der Test dient lediglich der Berichterstattung.
Die zweite Frage ist der Umgang mit externen Abhängigkeiten. Mocks und Stubs beschleunigen es, aber sie lügen: Sie testen, was Ihrer Meinung nach die Abhängigkeit tut, und nicht, was sie tut. Deshalb behalte ich mir echte Integrationstests für kritische Grenzen, Zahlung, Authentifizierung, Persistenz vor und verwende Doubles für den Rest sparsam.
Im dritten Bereich finden die Tests statt. Halten Sie sie in der Nähe des Codes, den sie überprüfen. Suiten in separaten Repositorys verrotten fast immer, da sie sich in einem anderen Tempo als der Produktionscode ändern.
Geschwindigkeit ist ein Merkmal der Suite
Eine langsame Suite ist eine Suite, die ignoriert wird. Wenn es eine halbe Stunde dauert, alles auszuführen, führt der Entwickler nur einen Teil davon oder gar nichts aus und entdeckt das Problem erst auf dem CI-Förderband, zu spät.
Das praktische Ziel besteht darin, dass die Einheitsschicht während der Entwicklung lokal in Sekundenschnelle ausgeführt wird. Dies erfordert Disziplin: parallelisierbare Tests, keine Abhängigkeit vom gemeinsamen Zustand, kein sleep, um auf etwas zu „warten“. Feste Wartezeiten sind die größte Ursache für Langsamkeit und Instabilität in echten Suiten.
In CI nach Stufen getrennt. Zuerst die Einheit ausführen, schnell scheitern und erst dann mit der Integration und End-to-End-Integration fortfahren. Es hat keinen Sinn, zehn Minuten mit einem Schnittstellentest zu verbringen, wenn bereits eine Grundregel verletzt ist.
Der wahre Feind: intermittierende Tests
Wenn es ein einzelnes Element gibt, das das Vertrauen in eine Suite zerstört, dann ist es der Test, der manchmal besteht und manchmal fehlschlägt, ohne dass sich etwas ändert. Es ist schlimmer, als keinen Test zu haben, weil es dem Team beibringt, Rot zu ignorieren.
Intermittierende Tests entstehen fast immer aus drei Quellen: Zeitabhängigkeit, Abhängigkeit von der Ausführungsreihenfolge und gemeinsamer Zustand über mehrere Fälle hinweg. Dies zu lösen ist eine Aufgabe der Architektur, nicht der Geduld. Jeder Test muss sein eigenes Szenario einrichten und bereinigen, ohne Rückschlüsse auf das zu übernehmen, was zuvor ausgeführt wurde.
Ich betrachte intermittierende Tests als einen Zwischenfall, nicht als Lärm. Wenn eines auftaucht, repariere ich es entweder oder entferne es. Die Aufbewahrung eines unzuverlässigen Tests in der Suite verseucht alle anderen.
Wer garantiert die Qualität der Suite?
Hier kommt die Managementvision zum Vorschein, die viele Teams ignorieren. Testcode ist Code. Es bedarf einer Überprüfung, Umgestaltung und Eigenverantwortung. Eine verlassene Suite verschlechtert sich im gleichen Maße wie jedes andere nicht gewartete System.
In den Teams, die ich leite, gilt die Regel, dass das Testen Teil der Definition von erledigt ist und keine separate Aufgabe ist, die an das Ende des Sprints verschoben wird. Und der Zustand der Suite (Ausführungszeit, intermittierende Fehlerrate) wird neben anderen, die wir überwachen, als technische Metrik berücksichtigt.
Im öffentlichen Kontext und bei Produkten, die mit sensiblen Daten umgehen, erhält dies ein weiteres Gewicht. Eine zuverlässige Suite ist Teil dessen, was es Ihnen ermöglicht, ein kritisches System zu ändern, ohne dafür beten zu müssen, dass etwas kaputt geht. Das ist Governance, keine technische Laune.
Fangen Sie klein an, aber beginnen Sie mit dem Zeichnen
Wenn Ihre Suite noch klein ist, ist dies der günstige Zeitpunkt, um die Architektur richtig hinzubekommen. Definieren Sie die Ebenen, stellen Sie sicher, dass Unit-Tests die Infrastruktur nicht berühren, erfordern Sie, dass jeder Test isoliert ist, und behandeln Sie Geschwindigkeit als Anforderung.
Wenn die Suite bereits umfangreich und mühsam ist, versuchen Sie nicht, alles neu zu schreiben. Stoppen Sie zuerst die Blutung: Eliminieren Sie die intermittierenden Blutungen, trennen Sie die Stufen im IC und schützen Sie mit neuen Tests nur das, was sich häufig ändert. Den Rest verbesserst du nach und nach.
Automatisierte Tests zum Nachweis, dass Code funktioniert, gibt es heute nicht. Sie existieren, um Ihnen den Mut zu geben, es morgen zu ändern. Eine gute Testarchitektur ist im Wesentlichen eine Versicherung gegen die Angst vor einer Weiterentwicklung des Systems.
Wenn Ihr Team bereits über Tests verfügt, aber das Vertrauen in diese verloren hat, lohnt es sich, die Architektur noch einmal zu prüfen, bevor Sie einen weiteren Fall schreiben. Ich habe auf dem Blog weitere Texte zum Thema Qualität und Software-Engineering, und wenn dies in Ihrem Unternehmen ein echtes Problem darstellt, ist diese Art von Gespräch lohnenswert.
Lesen Sie auch
- Automatisierte Testarchitektur: die wesentlichen Schritte zur Einrichtung von Grund auf
- Regressionstests: Versicherung gegen den Bruch dessen, was bereits funktioniert hat
- Softwaretestzyklus: Trends und eine Kurzanleitung für Führungskräfte
- Automatisiertes Testen: Warum ungetesteter Code Schulden ist
- Softwareleistung: Was reale Fälle über Qualität lehren
- Automatisiertes Testen: Architektur und Grundlagen