Test Driven Development

Die Nutzung von agilen Methoden ist kein uneingeschränkter Garant für bessere Software. Der Grund dafür ist, dass viele der klassischen Verfahrensweisen zur Qualitätssicherung im agilen Kontext vor einer Bewährungsprobe stehen. Denn wie soll in einem System mit häufigen Änderungen auf Dauer sichergestellt werden, dass die bereits als funktionstüchtig geltenden Bestandteile nicht durch zukünftige Nachbesserungen wieder in einen undefinierten Zustand verfallen?

Während das Wasserfallmodell den Test erst zu Projektende vorsieht und auch im vielfach eingesetzten V-Modell (siehe Abbildung 1) eine zeitlich klar definierte Abfolge vorliegt, ist es im agilen Umfeld unabdingbar, dass Tests aufgrund der Häufigkeit in der sie ausgeführt werden, tunlichst immer unter den exakt gleichen Bedingungen und mit möglichst geringem Aufwand durchgeführt werden können. Darüber hinaus sollten sie nach Möglichkeit zeitnahe zur Umsetzung der zu testenden Funktionalität bereit stehen. Denn nur so kann gewährleistet werden, dass sie mit dem steten Wandel schritthalten.

Das V-Modell und die testgetriebene Entwicklung
Abbildung 1: Das V-Modell und die testgetriebene Entwicklung

Test Driven Development

Das größte Problem des klassischen Testens ist in diesem Zusammenhang also, dass es in aller Regel nachgelagert geschieht. Es wird erst dann ausgeführt, wenn es auch etwas zu testen gibt. Dies scheint auf den ersten Blick trivial, denn soll etwas getestet werden ist vermeintlich auch ein entsprechender Testgegenstand von Nöten.

Zwar können die Testfälle und ihre Daten aus der Spezifikation abgeleitet werden, ohne eigentlichen Testgegenstand gibt es bei der Ausführung aber scheinbar kein auswertbares Ergebnis. Genau dieses Dogma gilt für automatisierte Tests  nicht. Während die ständige manuelle Ausführung auf Dauer unbezahlbar würde, können automatisierte Tests getrost auch kurz vor der eigentlichen Implementierung verfasst, sowie ausgeführt werden und prüfen dann vorrübergehend nur eine Hülle des späteren Testgegenstandes. Eine Hülle wie sie beispielsweise von einer Schnittstellenbeschreibung vorgegeben ist.

In diesem Fall stellt der Test eine Art automatisierter Spezifikation dar, der Anforderungen zunächst nicht erfüllt werden (roter Beriech in Abbildung 2). Der Entwickler kann während der Implementierungsphase seinen Code gegen diese prüfen und erhält damit sofort ein Feedback ob seine Arbeit den Anforderungen entspricht. Ist dieser Status erreicht (grüner Bereich), hat er einen gesicherten Zustand des Quellcodes und kann jenen umstrukturieren (gelber Bereich). Bei neuen Anforderungen oder tiefgreifenden Änderungen schlagen die Tests erneut fehl (erneut roter Bereich) und müssen zunächst wieder korrekt erfüllt werden (erneut grüner Bereich).

Aus dieser einfachen Handlungsreihenfolge ergeben sich feingranulare Strukturen. Diese führen zu einer sehr hohen Testabdeckung, mit welcher Fehler frühzeitig gefunden und deren Behebung vereinfacht wird. Darüber hinaus werden Schnittstellen und deren Implementierung robuster als bei klassischen Verfahren definiert. Dies erlaubt erst die hohe Anpassungsfähigkeit des Quellcodes, welche für agile Softwareprojekte so essentiell wichtig ist.

Der Ablauf der testgetriebenen Arbeitsweise
Abbildung 2: Der Ablauf der testgetriebenen Arbeitsweise

Als eine der wichtigsten Eigenschaften von automatisierten Tests gilt darüber hinaus deren Lesbarkeit. Denn sie können im Grunde nicht nur als Prüfung der Funktionalität, sondern auch als eine Art Dokumentation der selbigen verstanden werden. Durch ihre Nähe zur Funktionalität die sie prüfen und ihrem klar strukturierten Aufbau, schildern sie das Verhalten des zu testenden Codes auf eine Weise wie es normal geschriebener Text nicht könnte. Da ihr eigenes Ergebnis überdies vollkommen abhängig vom Testgegenstand ist, teilen sie dem Betrachter automatisch mit wenn sie nicht mehr aktuell sind.

Behavior Driven Development

Diese Lesbarkeit erstreckt sich bei Komponententests jedoch einzig auf den Personenkreis der auch die entsprechende Programmiersprache versteht und das verwendete Testframework kennt. Domänenfremde Personen wie zum Beispiel Testmanager, Projektleiter oder sogar Endanwender können der feinen Granularität und Detailgenauigkeit nur wenig abgewinnen.

Eine zweite Unzulänglichkeit wird bei der Betrachtung des gesamten Entwicklungsprozesses offenbar. Mit TDD verfasste Tests sind hervorragend geeignet um Teile der Software anhand ihrer Spezifikation zu verifizieren, nicht aber um sie gegen die Akzeptanzkriterien zu validieren. Gerade diese sind es aber die befriedigt werden wollen und somit bei einer Überprüfung noch vor der Implementierung kommen sollten.

Aus diesen Gründen ist aus dem bekannten Test Driven Development das sogenannte Behavior Driven Development oder auch Acceptance Test Driven hervor gegangen. Bei diesem verschmelzen Tests und Spezifikation dank der Nutzung bestimmter Werkzeuge und Schlüsselworte so miteinander, dass die Testergebnisse in klarsprachlicher Weise ausgewertet werden können. Dazu wird insgesamt von der Beschreibung einzelner Funktionalitäten weg und zur Schilderung eines erwarteten Verhaltens (Behavior) hin gegangen. Auf diese Weise bedarf die Definition der einzelnen Testfälle keines Hintergrundwissens mehr zur Architektur des Programms, wodurch sie auch von Nichtentwicklern nachvollzogen werden kann und führt sogar soweit, dass häufig nicht einmal mehr von Testfällen sondern von Spezifikationen gesprochen wird.

Behaviour Driven Develoment kann nicht als eine Konkurrenz zum Test Driven Development verstanden werden. Denn ersteres dient vor allem der Validierung der Software sowie der Prüfung der Systemintegration, während letzteres der Verifikation  und damit der Sicherung von funktionaler Korrektheit dient. Demnach ist es durchaus sinnvoll beides in Kombination zu verwenden.

Aufwand

Durch die Besonderheit, dass neben der eigentlichen Produktentwicklung von Entwicklern auch das Schreiben der Tests erwartet wird, führt die testgetriebene Entwicklung zunächst zu einem höheren Aufwand, als dies bei klassischen Verfahren üblich ist. So muss eine entsprechende Infrastruktur geschaffen, weitere Werkzeuge erlernt und zusätzlicher Code geschrieben werden, der nicht sofort in nutzbaren Features mündet. Dies mag zunächst abschrecken, zeigt aber im Grunde nur den Aufwand, der andernfalls viel später im Projekt anfällt. Statt der Aufwände für lange Test- und Bugfixingphasen gegen Ende des Projekts, wird ein Großteil der Qualitätssicherung bereits zu einem Zeitpunkt vorbereitet, indem ein Projektteam durchaus noch komfortabel handeln kann. Dieser Aufwand wiederum sinkt mit zunehmendem Projektverlauf, da die Infrastruktur häufig nur einmal grundlegen erstellt und anschließend nur noch punktuell angepasst werden muss.

Ab wann lohnt sich TDD?
Abbildung 3: Ab wann lohnt sich TDD?

Fazit

Der Einsatz der in diesem Artikel vorgestellten Methoden stellt teilweise einen erheblichen Bruch mit den klassischen Vorgehensweisen in der Softwareentwicklung dar, ermöglicht jedoch eine Qualitätssicherung und Dokumentation wie sie sonst nur schwer möglich ist. So verrät die Software im Grunde selbst ihren aktuellen Ist-Stand ohne dass externe Ressourcen gepflegt werden müssen, die unter Umständen schnell veralten. Durch die Kombination der unterschiedlichen Ansätze kann dabei die Qualität und ein umfassendes Projektverständnis über alle Abstraktionsebenen hinweg sichergestellt werden.

Dieser Beitrag wurde verfasst von: