Praktiken II: Automatisierte Akzeptanztests

Nach längerer Zeit nun der zweite Teil meiner Serie über agile Prakitken. Bisher finden Sie in dieser Kategorie die folgenden Einträge:

Der zweite Teil beschäftigt sich mit automatisierten Akzeptanztests:

Auch agile Entwicklung startet mit den fachlichen Anforderungen. Allerdings werden sie direkt als Akzeptanztests aufgeschrieben, statt in Anforderungsdokumenten. Akzeptanztests sind fachliche Beschreibungen dessen, was das System können soll und zwar so, dass sie automatisch ausgeführt werden können. Automatisch ausführbare Tests steuern die Anwendung und überprüfen deren Ergebnisse ohne menschlichen Eingriff. Der Weg zu diesen Akzeptanztests ist noch eher uneinheitlich, man geht aber in der Regel von den geplanten geschäftlichen Abläufen aus (siehe dazu auch „Use Cases oder User Stories„).

Die Fachexperten im Team schreiben die Akzeptanztests, möglichst bevor das System die Funktionalität unterstützt. Diese Tests werden natürlich zunächst scheitern und es ist Aufgabe der Entwickler, sie zum Laufen zu bringen. Damit bilden Akzeptanztests ein klares Abschlusskriterium für eine neue Aufgabe, weil sie definieren, wann eine Aufgabe als erledigt akzeptiert wird: Die Aufgabe ist genau dann erledigt, wenn alle ihre Akzeptanztests auf dem Build-Server laufen und die Fachexperten keine neuen Tests mehr finden, die scheitern.

Der letzte Halbsatz soll dabei nicht das Tor zur „Hier-stopfe-ich-alles-hinein-was-mir-einfällt-Hölle“ öffnen, sondern deutlich machen, dass eine Anforderung erst dann abgeschlossen sein kann, wenn sie wirtschaftlich funktionsfähig ist. Ich möchte damit Exzessen vorbeugen, wie sie in den Neunziger Jahren vorkamen. Eine Firma versprach damals „fehlerfreie“ Software. Der Trick: Der Auftraggeber musste die Spezifikation als automatisierte Tests zuliefern, als „Fehler“ wurden nur Abweichungen der Ergebnisse von den Tests definiert. Erweiterungen der Tests wurden als Spezifikationsänderung und damit kostenpflichtige Vertragsänderung interpretiert. Zwar hatte diese Firma den Gedanken des Festpreises konsequent zu Ende gedacht, bankrott gegangen ist sie dennoch, weil sie ihre Kunden überfordert hat.

Von solchen Exessen einmal abgesehen, läuft es in der Praxis meistens darauf hinaus, dass die Fachexperten zuerst die „Gutfälle“ anlegen. Fehler- und Problemfälle werden größtenteils nachgeschoben, oft auch „esoterische“ fachliche Randfälle – in der Regel auf Nachfrage der Entwickler.

Wer verlangt, dass die Fachexperten alle Akzeptanztests vor Beginn der Arbeiten fertig stellen, verkennt die fachliche Komplexität eines Sofwaresystems und ignoriert eine Grundannahme agilen Arbeitens: Dass man das Potenzial des Systems erst erkennen kann, wenn man mit ihm arbeitet und von ihm lernt. Ein süffisantes „da hätten Sie aber früher kommen müssen“ auf zusätzliche Akzeptanztests zeigt höchstens, dass man das Wasserfalldenken noch nicht überwunden hat.

Akzeptanztests werden aber nicht nur für neue Anforderungen genutzt, sondern auch, um Fehlermeldungen in den Prozess einzuschleusen. Laufen alle Tests, so bedeuten dennoch auftretende Fehler zunächst, dass die Testfälle Lücken haben. Der Tester schreibt also einen Akzeptanztest, der das Problem reproduziert und gibt ihn dann in die Entwicklung. Das erspart auch gleich unnötige Zyklen zwischen Testern und Entwicklern, weil die Entwickler das Problem nicht nachvollziehen können.

Akzeptanztests werden in einer eigenen Umgebung so aufgeschrieben, dass das Entwicklungsteam sie vollautomatisch ausführen und überprüfen kann. Das ist die Voraussetzung dafür, sie in den Entwicklungsprozess einzubinden und nach jeder Änderung wieder ablaufen zu lassen: In agilen Projekten laufen alle jemals zum Laufen gebrachten Akzeptanztests mehrfach täglich auf einem Build-Server – oft mehrere tausend Tests von denen kein einziger scheitern darf. Natürlich muss man dafür in der Lage sein, die Tests, die schon einmal liefen von jenen zu trennen, die neue Anforderungen festlegen und daher noch nie liefen. Letztere dürfen am Build-Server nicht laufen.

Warum dieser Aufwand? Die automatisierten Tests sichern den bisher erreichten Leistungsumfang ab: Eine einmal realisierte Funktionalität wird durch die Akzeptanztests nach jeder Änderung wieder überprüft. Scheitert kein Test, kann man sich hinreichend sicher sein, dass man nicht versehentlich etwas zerstört hat, was schon einmal funktionierte.

Wenn auch nur ein einziger Akzeptanztest scheitert, muss das Team das Problem mit höchster Priorität lösen, schließlich hat jemand seit dem letzten Testlauf etwas kaputt gemacht, was vorher ging. Glücklicherweise ist das meistens aber nicht so dramatisch, wie es sich anhört: Weil der letzte Testlauf höchstens ein paar Stunden her ist, können nur wenige Codeänderungen die Tests zerstört haben. Sie zu prüfen und zu korrigieren ist oft nur eine Sache einiger Minuten. Wenn man allerdings das Problem mit dem freundlichen Komentar „ach, der Test geht schon lange nicht mehr“ ignoriert, werden im Laufe der Zeit immer mehr Tests scheitern. Mit den Testfällen erodiert dann auch die Funktionalität. Das führt dann zu aufwändigen Fehleranalysen und Panikmaßnahmen kurz vor dem Release, also zu Überstunden und schlechtem Code – typischen Phänomenen eines Wasserfallansatzes.

Um das zu vermeiden, stellen sich manche Teams rote Lavalampen in den Flur, die automatisch angeschaltet werden, sobald ein Akzeptanztest scheitert. Andere Teams schicken Meldungen an alle Entwickler oder zeigen den aktuellen Buildstatus als Hintergrundfarbe auf der Projekthomepage an. Der Phantasie sind hier kaum Grenzen gesetzt. Diese Maßnahmen zeigen alle, dass das ganze Team dafür verantwortlich ist, die Tests lauffähig zu halten. „Ich war das nicht“ ist eine Ausrede, die nicht zählt.

Wie wichtig automatisierte Tests für die Entwicklung in kurzen Inkrementen sind, erlebe ich immer wieder bei der Einführung agiler Techniken, wenn noch eine große, schlecht abgedeckte Codebasis zu warten ist: In den ersten Monaten haben diese Teams oft große Probleme, zumindest einmal täglich stabile Software auszuliefern. Erst wenn ausreichend Tests aufgebaut worden sind, entsteht der „ruhige Fluss“ neuer Funktionalität, der typisch ist für agile Entwicklung.

Aus diesen Beschreibungen können wir einige Anforderungen an ein Testsystem ableiten:

  • Man muss Tests schreiben können, bevor die Funktionalität implementiert ist
  • Tests sollten möglichst fachlich beschrieben werden, Nicht-Programmierer müssen sich schnell einarbeiten können
  • Die Tests müssen unbeaufsichtigt ohne menschlichen Eingriff laufen können
  • Die Testauswertung muss vollautomatisch geschehen, also ohne dass ein Mensch Protokolle inspizieren müsste
  • Schlägt ein Test fehl, müssen die Entwickler ausreichend Diagnoseinformationen bekommen, um das Problem schnell zu finden

Als defacto Standard für Akzeptanztests hat sich trotz einiger Schwächen das FIT Framework etabliert, insbesondere in seiner Variante als FitNesse. Die Idee stammt vom Wiki-Erfinder Ward Cunningham: Fachexperten erfassen ihre Testfälle als HTML-Seiten bei FIT, beziehungsweise Wiki-Seiten bei FitNesse. Dazu stehen ihnen verschiedene Tabellenarten zu Verfügung. Mit ein bisschen Geschick kann man sogar entsprechend strukturierten Text verwenden.

Ein einfacher Fit-Test mit Testergebnis Die Abbildung zeigt einen einfachen Fit-Test für einen Taschenrechner. Die Tabelle definiert verschiedene Parameter für die Division und die erwarteten Ergebnisse. Allerdings war unser Tester etwas schwach im Kopfrechnen, weshalb der Test auch fehlschlägt, wie man leicht an den rot hinterlegten Zellen sieht. Ein Fit Test ähnelt also durchaus einer geläufigen Testspezifikation, wie man sie auch von traditionellen Testteams kennt. Bei FitNesse können die Testfälle zudem wie in jedem anderen Wiki gruppiert, strukturiert und verwaltet werden.

Was leistet nun das Framework? Es liest die Seiten aus und wandelt die Tabellen und Texte um in Aufrufe an eine Zwischenschicht, die sogenannten Fixtures, die mit den Informationen aus den Tabellen aufgerufen werden. Diese Fixtures müssen von Entwicklern des Teams geschrieben werden. Sie rufen mit den übergebenen Daten die Anwendung auf und geben die angeforderten Ergebnisse zurück an das Framework. Sie stellen also die Adapter dar, mit denen die fachlich formulierten Testfälle in Systemaufrufe umgesetzt werden.

Fehlt die zu einer Tabelle gehörende Fixture noch, oder reagiert das System nicht so, wie vorgesehen, scheitert der Test kontrolliert. Man kann mit dem Fit Framework also Tests verfassen, bevor die zu testende Funktionalität überhaupt programmiert wurde. Die Entwickler können diese Tests dann nutzen, um sicher zu stellen, dass sie fachlich richtig liegen. Zudem lassen sich die Tests sehr elegant in automatische Buildprozesse integrieren, so dass man immer die Gewissheit hat, alte Fachlichkeit nicht versehentlich zerstört zu haben.

Mit Versuchen, Akzeptanztests mit sogenannten Oberflächen-Rekordern zu erstellen, habe ich schlechte Erfahrungen gemacht. Diese Werkzeuge benötigen bereits eine fertig programmierte Oberfläche. Man kann also nicht Testfälle bauen, bevor die Software geschrieben wurde. Außerdem sind solche Tests langsam und sehr empfindlich gegen Oberflächenänderungen, die weitaus häufiger vorkommen, als fachliche Änderungen. Der Wartungsaufwand für diese Tests ist damit deutlich höher, als der von FIT-Tests. Oberflächen-Rekorder sind wertvolle Werkzeuge, um komplexe Last- und Skalierungstests durchzuführen. Für fachliche Akzeptanztests im Sinne testgetriebener Entwicklung sind sie ungeeignet.

Interessant finde ich die Variante, das Selenium Framework mit FitNesse zu koppeln: Selenium ist ein frei verfügbares Framework, um die Tests von Web-Servern zu automatisieren. FitNesse kann so die Interaktionen mit dem Web-Server über Selenium steuern und die Ergebnisse überprüfen. Allerdings empfiehlt sich diese Technik nur, wenn die Geschäftslogik bereits weitgehend mit Tests abgedeckt ist, die unabhängig von der Oberfläche arbeiten. Das FitNesse-Selemium-Tandem kann dann schwere Integrationsfehler zwischen Oberfläche und Geschäftslogik aufdecken. Man sollte allerdings der Versuchung widerstehen, eine vollständige Abdeckung der Oberfläche mit diesen Tests anzustreben.

Tests, die bewusst unterhalb der Oberfläche aufsetzen haben noch einen anderen Vorteil: Sie erzwingen eine saubere Trennung zwischen Oberfläche und Anwendungskern und leisten damit einen Beitrag zu guter Architektur. Das vereinfacht dann auch den Einbau von Service-Schnittstellen oder die Einbindung in eine SOA.

Ich danke Johannes Link und meiner Frau Susanne für die Unterstützung bei diesem Eintrag

Links und Buchtipps zu Akzeptanztests

  • Rick Mugridge, Ward Cunningham: FIT for Develeloping Software – Framework for Integrated Tests, Prentice Hall, 2005, ISBN 0-321-26934-9
    Eine Einführung in die Prinzipien von FIT und FitNesse. Für Entwickler ist das Buch etwas unhandlich strukturiert und ich persönlich habe darin keine Antworten gefunden, die ich nicht auch in der Online-Hilfe gefunden hätte. Wer aber gerne ein Nachschlagewerk aus Papier hat, ist hiermit sicher gut bedient.
  • Gojko Adzic: Test Driven .NET Development with FitNesse, Neuri Limited, 2008, ISBN 978-0-9556836-0-2
    Eine sehr gute Einführung in den Einsatz von FitNesse unter .NET, das aber genau so gut auch für die Java-Fassung verwendet werden kann. Das Buch vertieft ein einfaches Beispiel immer weiter, bis (fast) alle Aspekte von FitNesse ausgeleuchtet sind. Didaktisch sehr gut aufbereitet. Zwei kleine Schwachpunkt: Zwar wird die Integration in Open Source Build-Systeme wie CruiseControl.NET diskutiert, Visual Studio und der Team Foundation Server werden praktisch nicht behandelt. Das lässt nicht nur viele Anwender außen vor, sondern umschifft auch eines der kritischsten Probleme im Umgang mit FitNesse unter .NET. Zum zweiten ist das Beispiel für die Kopplung zwischen Selenium und FitNesse ein wenig sehr generisch. Stärker fachlich geprägte Tests wären ein besseres Vorbild gewesen.
    Interessant auch der Vertriebsweg: Das Buch ist nicht über die üblichen (Internet-)Buchhändler zu beziehen, sondern im Eigenverlag entweder als PDF oder per On-Demand-Druck – zuverlässig nach drei bis fünf Tagen.
  • Cem Kaner ,James Bach, Brett Pettichord: Lessons Learned in Software Testing, John Wiley & Sons, New York, 2002, ISBN 0-471-08112-4
    Mein Lieblingsbuch zum Testen von Software. Der wichtigste Satz ist Programm: „Testing is the headlights of the project“. Dem ist kaum noch etwas hinzuzufügen
  • Brian Maricks Web-Site und Blog: http://www.exampler.com
    Der führende Experte zu Tests in agiler Entwicklung – und ein begnadeter Querdenker
  • Web-Site von FitNesse: http://www.fitnesse.org
    Hier kann man näheres über FitNesse lesen, mit etwas Glück auch ausprobieren und sich FitNesse herunterladen. Einzige Voraussetzung: Eine Java Runtime – auch für die .NET-Fassung!