Es gibt mehrere Gründe für das Schreiben automatisierter Tests, was zum Teil relativ einfach erscheinen mag. Das Schreiben „guter“ automatisierter Tests ist jedoch wesentlich schwieriger und erfordert umfangreiche Erfahrung und bewusstes Training.
In diesem Beitrag habe ich einige (hochrangige) Ziele zusammengestellt, die überprüft werden müssen, damit die automatisierten Tests gut werden. Die Ziele sind in zwölf Merkmalen definiert, und wenn sie erfüllt sind, ist die Definition von „guten“ automatisierten Tests erreicht.
Hier sind einige übergeordnete Ziele, die zutreffen könnten:
Tests sollten uns helfen, die Qualität zu verbessern.
Tests sollten uns helfen, das System zu verstehen.
Tests sollten das Risiko reduzieren (nicht erhöhen).
Tests sollten leicht durchführbar sein.
Tests sollten einfach zu schreiben und zu warten sein.
Tests sollten minimale Wartung erfordern, wenn sich das System um sie herum weiterentwickelt.
Wenn Sie testgetriebene Entwicklung (TDD – test-driven development) oder verhaltensgetriebene Entwicklung (BDD – behavior-driven development) verwenden, können Sie mit Hilfe von Tests erfassen, was das System tun wird, bevor Sie mit der Entwicklung beginnen. Das Durchdenken verschiedener Szenarien, um sie in Tests umzuwandeln, hilft uns, die Bereiche zu identifizieren, in denen die Anforderungen mehrdeutig oder widersprüchlich sind. Eine solche Analyse verdeutlicht das Ziel der Spezifikation, was zu einem genaueren Entwurf führt und die Qualität der Software verbessert.
Automatisierte Tests finden Fehler, aber das ist nicht der Hauptzweck der Testautomatisierung. Automatisierte Tests verhindern, dass Fehler eingeführt werden. Stellen Sie sich automatisierte Tests als Fehlerabwehr vor, die verhindern, dass Fehler in unsere Software zurückkommen, nachdem wir sichergestellt haben, dass sie fehlerfrei ist. Wenn wir gute und vollständige Regressionstests haben, wird es keine Fehler geben, weil die Tests die Fehler aufzeigen, bevor wir unseren Code überhaupt einchecken.
Wenn die automatisierten Tests relativ klein sind (d. h. wir testen in jedem Test nur ein einziges Verhalten), können wir den Fehler schnell ausfindig machen, je nachdem, welcher Test fehlschlägt. Um dies zu erreichen, müssen wir Tests für alle möglichen Szenarien schreiben, um jede Einheit der Software abzudecken. Die Tests dürfen niemals Mehrdeutigkeiten enthalten. Daher ist es wichtig, die Tests so klein und trivial wie möglich zu halten (geringe Komplexität, konsistentes Format und Prüfung eines einzigen Verhaltens in jedem Test).
Automatisierte Tests können klar aufzeigen, wie der Code funktionieren sollte. Sie zeigen, was das Ergebnis sein sollte (sie geben das erwartete Ergebnis einer oder mehrerer Anweisungen an).
Wenn wir wissen wollen, wie das System etwas tut, können wir den Debugger starten, den Test ausführen und den Code Schritt für Schritt durchgehen, um zu sehen, wie er funktioniert. Die Unit-Tests fungieren als eine Art Dokumentation für das System.
Älteren Code zu ändern ist riskant, weil wir oft nicht wissen, was wir kaputt machen könnten, und es ist auch schwer zu wissen, ob wir etwas kaputt gemacht haben! Wir müssen sehr langsam und sorgfältig arbeiten und viele manuelle Analysen durchführen, bevor wir Änderungen vornehmen.
Wenn wir jedoch mit Code arbeiten, der über eine automatisierte Testsuite verfügt, können wir viel schneller arbeiten. Die Tests fangen unerwartete Nebeneffekte von Änderungen auf und lassen uns wissen, ob wir etwas kaputt gemacht haben. Auf diese Weise wirken die automatischen Tests wie ein Sicherheitsnetz, das uns dazu bringt, Risiken einzugehen.
Wir müssen darauf achten, dass wir durch automatisierte Tests keine neuen Arten von Problemen in das System einführen. Halten Sie den Testcode vom Produktionscode getrennt, um zu vermeiden, dass testspezifische Abhängigkeiten im System entstehen (besonders wichtig für Unit-Test-Code). Der gesamte testbezogene Code und die Bibliotheken sollten ausschließlich im Test-Build und in der Testumgebung integriert werden. Testabhängigkeiten und Testcode dürfen im endgültigen Produktionscode niemals enthalten sein.
Es gibt vier spezifische Merkmale, die die Ausführung automatisierter Tests erleichtern. Mit diesen vier Merkmalen können Sie einfach auf eine Schaltfläche klicken (oder besser noch automatisch auslösen), um das wertvolle Feedback zu erhalten, das die Tests liefern:
Die Tests müssen vollständig automatisiert sein, so dass sie ohne Aufwand ausgeführt werden können.
Die Tests müssen selbstauswertend sein, so dass sie Fehler ohne manuelle Überprüfung erkennen und melden können.
Die Tests müssen wiederholbar sein, damit sie mehrfach mit den gleichen Ergebnissen durchgeführt werden können.
Jeder Test sollte unabhängig sein, so dass er für sich selbst laufen kann.
Ein Test, der ohne jeden manuellen Eingriff durchgeführt werden kann, ist ein vollautomatischer Test. Die Erfüllung dieses Merkmals ist eine Voraussetzung für die Erfüllung der anderen.
Ein Test mit Selbsteinschätzung kann alles kodieren, was der Test braucht, um zu überprüfen, ob das erwartete Ergebnis korrekt ist. Der Test benachrichtigt uns nur, wenn das Ergebnis nicht genehmigt wurde; folglich erfordert ein sauberer Testlauf keinerlei manuellen Aufwand.
Ein wiederholbarer Test kann immer wieder durchgeführt werden und liefert immer noch genau die gleichen Ergebnisse, ohne dass ein menschliches Eingreifen oder eine Analyse zwischen den Durchläufen erforderlich ist.
Wenn wir das Verhalten in einem Teil eines Systems ändern, sollten wir erwarten, dass eine kleine Anzahl von Tests von unseren Änderungen betroffen sind. Einer der Vorteile der Testautomatisierung ist die einfache Durchführung von Änderungen. Wir sollten daher stets darauf achten, dass unsere Tests nicht das Gegenteil bewirken (Änderungen erschweren). Tests sollten nur minimale Wartung erfordern, wenn sich das System um sie herum weiterentwickelt.
Das Hauptaugenmerk sollte auf den Tests liegen und nicht darauf, wie man sie programmiert. Das bedeutet, dass die Tests einfach/trivial sein müssen (einfach zu lesen, einfach zu schreiben und einfach zu warten). Wir sollten uns bemühen, eine Bedingung pro Test zu überprüfen, indem wir für jede einzigartige Kombination von Bedingungen eine eigene Testmethode erstellen. Jede Testmethode sollte das System über einen einzigen Pfad im System testen.
Eine Bibliothek von Hilfsmethoden, die eine domänenspezifische Testsprache aufbaut, ermöglicht es der Person, die den Testcode schreibt, die Konzepte auszudrücken, die sie testen möchte, ohne ihre Gedanken in viel detaillierteren Code übersetzen zu müssen.
Halten Sie den Testcode vom Produktionscode getrennt (behalten Sie die Struktur und Logik des Produktionscodes bei, aber in einer parallelen Struktur). Jeder Test sollte sich auf ein einziges Problem konzentrieren, um komplizierte und unklare Tests zu vermeiden.
Es gibt einen Unterschied zwischen einem Test und einem guten Test, aber es ist oft schwierig zu wissen, wie man einen „guten“ Test definiert. In dieser Checkliste habe ich 12 Merkmale für gute Testautomatisierungspraktiken aufgezeigt, die wiederum zu einfach zu schreibenden Tests und angemessener Wartung führen - beides Faktoren, die für ein System sehr wichtig sind.