Funktionsweise und Zusatznutzen von Strict TDD

Obwohl inzwischen viele Entwickler auf automatisierte Tests setzen, praktizieren immer noch nur wenige Test-Driven Development (TDD) in Reinform. Dabei bringt das strikte Befolgen des Prozesses neben dem Gewinn an Sicherheit noch einigen Zusatznutzen. Wer also ohnehin viel Zeit in das Schreiben von Tests investiert, sollte das Potenzial von TDD nicht verschenken.

Know-how  –  23 Kommentare

In aller Regel erwarten Kunden qualitativ hochwertige Software. Klassischerweise führen deshalb Tester manuelle Tests mit der zuvor erstellten Software durch und prüfen sie so gegen die Spezifikation. Um bei der Umsetzung neuer Features nicht als Seiteneffekt Fehler in bestehenden Funktionen zu provozieren, sind diese durch sogenannte Regressionstests erneut zu kontrollieren. Agile Methoden fordern eine stark erhöhte Taktrate der Releases, um schneller Feedback zu erhalten und Features baldmöglich produktiv nutzen zu können. Dadurch werden aber mit wachsendem Funktionsumfang manuelle Regressionstests unwirtschaftlich bis unmöglich.

Zum Umgehen dieses Dilemmas wenden deshalb viele Projekte automatisierte Regressionstests an. Um Qualität früh im Entwicklungsprozess zu verankern, setzen zunehmend mehr Entwickler parallel zu den Testern auf automatisierte Entwicklertests. Meist baut ein Continuous-Integration-Server wie Jenkins die Software bei jedem Check-in in das Versionskontrollsystem oder zumindest einmal pro Nacht im "nightly build". Anschließend starten sie die Tests und informiert die Entwickler per Mail, wenn sie fehlschlagen. Somit fungieren die Tests als Sicherheitsnetz, um bestehende Features des Systems zu konservieren.

Viele Entwickler glauben, damit bereits testgetriebene Entwicklung [1] im Projekt einzusetzen, bleiben aber bei automatisierten Tests stehen und lassen wesentliche Elemente von TDD aus. Das ist schade, denn TDD kostet nicht mehr als das ohnehin durchgeführte Schreiben automatisierter Tests, kann aber mehr. Der Artikel beleuchtet Funktionsweise und Zusatznutzen von "Strict TDD", wie Minimierung unnötigen Codes, schnelleres Feedback, fokussierteres Arbeiten und besseres Design.

Im Anfang ist der Test

"Klassisch" erstellen Entwickler zuerst den Produktivcode und erst danach die Tests ("test last"). Mit den ersten Projekten Ende der 90er-Jahre, bei denen die agile Entwicklungsmethode "Extreme Programming" (XP) [2] zum Einsatz kam, wurde das sogenannte "test-first programming" bekannt. Dabei drehen Entwickler die Reihenfolge um: Sie schreiben bereits vor der eigentlichen Implementierung einen Test, der fehlschlägt ("red"). Erst dann erstellen sie den Produktivcode, sodass der Test erfolgreich durchläuft ("green"). Damit verhilft das Test-first-Vorgehen zu einer besseren Disziplin beim Schreiben der Tests, denn diese werden nicht einfach weggelassen, wenn gegen Ende wie üblich die Zeit knapp wird.

"Test first" motiviert zudem stärker als das Test-last-Vorgehen. Der Wechsel von Rot auf Grün signalisiert Entwicklern einen Fortschritt in den erstellten Features. "Test last“ hingegen ist langweilig und hat einen destruktiven und demotivierenden Charakter. Im "produktivste" Fall (Wechsel von Grün auf Rot) findet man einen Fehler im eigentlich schon fertig implementierten Code.

In der Praxis wird ein großer Anteil der Features einer Software von keinem Benutzer verwendet. Die Disziplin des Requirements Engineering hat daher zum Ziel, diesen unnötigen Implementierungsaufwand zu reduzieren. Aber auch Entwickler neigen gerade beim Test-last-Vorgehen zum Phänomen "you ain't gonna need it" (YAGNI): Sie entwickeln Code, den Auftraggeber nicht brauchen. Das kann eine nie aufgerufene Methode sein, aber auch ein Feature, das zwar Entwickler, nicht aber die tatsächlichen Benutzer für sinnvoll erachten.

Von Test zu Behaviour-Driven Development

Das Test-first-Prinzip fordert, Produktivcode nur schreiben zu dürfen, wenn er dazu dient, einen Test auf Grün zu bringen. Das hilft dabei, sich darauf zu konzentrieren, nur wirklich notwendigen Code zu schreiben. Beim Erstellen eines Tests vor der Umsetzung müssen sich Entwickler erst einmal genauer damit auseinandersetzen, welche Features sie überhaupt umsetzen sollen, und sich somit an den Anforderungen ausrichten. Beim Test-last-Vorgehen hatte der Test nur die Aufgabe der Validierung. Bei "test first" bekommt er plötzlich eine weitere Rolle: Er wird zur Spezifikation des zu implementierenden Codes.

Diese Beobachtung hat Dan North 2007 dazu veranlasst, Behaviour-Driven Development (BDD) aus der Taufe zu heben und damit diesen Umstand auch begrifflich explizit zu machen: Aus "test" wird "behaviour". Der Begriff "test" wird mit Validierung und damit als Test-last-Vorgehen assoziiert. Eine "specification by example" hingegen beschreibt das umzusetzende Verhalten anhand eines konkreten Beispiels bereits, bevor der implementierende Code existiert, also "test first".

BDD hat sich vor allem auf Ebene der Akzeptanztests etabliert, auch wenn die Idee genauso für Unit-Tests gilt. In den Fokus rückt damit das Finden und Dokumentieren der für die gegebene Problemstellung richtigen Anforderungen. Im Idealfall setzen sich in einem "specification workshop" die verschiedenen Projektbeteiligten mit ihren unterschiedlichen Blickwinkeln auf die Anforderungen gemeinsam an einen Tisch: Die "three amigos", Auftraggeber, Entwickler und Tester, entwickeln zusammen anhand von Beispielen ein einheitliches Verständnis der Akzeptanzkriterien.