Claudius A. (25) aus Hildesheim fragt: Wie soll ich eigentlich etwas testen, das noch gar nicht existiert?
Dr. T. D. Dommer antwortet : Wir haben uns daran gewöhnt, Produktivcode zu schreiben, der vorher auch nicht existiert hat. Dabei denken wir uns im Voraus einen Zusammenhang, in dem dieser Produktivcode sinnvoll erscheint, und schreiben ihn einfach hin, lassen ihn gegebenenfalls vom Compiler überprüfen. Mit testgetriebener Entwicklung machen wir einen Teil dieses Denkprozesses explizit und denken den Produktivcode aus der Sicht seines ersten Benutzers: dem Test. Wir stellen uns also beim Testen einfach mal vor, welche Klassen und Methoden wir uns wünschen würden, um einen bestimmten Sachverhalt zu testen. Auch wenn es diese Klassen und Methoden noch gar nicht gibt. So entsteht der Test zuerst. Viele Entwicklungsumgebungen erlauben uns dann das automatische Erstellen von Klassen- und Methodenrümpfen, die wir dann „nur noch“ mit Leben füllen müssen. Dies beantwortet erst einmal die Mechanik, wie wir etwas testen können, das noch nicht existiert.
Meist interessiert aber auch die Frage: Warum sollte ich so vorgehen? Hier gibt es vor allem zwei große Vorteile hervorzuheben:
- Der entstehende Produktivcode wird strukturiert aus der Sicht eines Benutzers der entsprechenden Klassen und Methoden. Das führt zu besserem Design, als aus der Sicht einer einzelnen Datenstruktur heraus Methoden anzubieten. Es führt zuweilen sogar zu deutlich weniger Produktivcode, weil scheinbar notwendige Methoden (was man hinzufügen kann, muss man auch löschen können) vom Test gar nicht benötigt werden. Dann sollten sie auch noch nicht erstellt werden.
- Methodisch hat der Ansatz der testgetriebenen Entwicklung den Vorteil, dass nur getesteter und testbarer Code entsteht. Das systematische Testen nach der Erstellung des Produktivcodes hat nämlich zwei Nachteile: Zum einen wird es oft einfach weggelassen, weil es an Disziplin mangelt oder der (Zeit-)Druck zu hoch scheint. Zum anderen merkt man dann erst beim Testen, dass der Code schlecht testbar ist und aufwändig umgebaut werden müsste. Diesen Aufwand scheut man dann aber, obwohl es allgemein als anerkannt gilt, dass schlecht testbarer Code definitiv auch schlecht entworfener Code ist. Viele heutige Systeme sind over-designed und under-tested.
Domenikus B. (29) aus Dresden zweifelt: Muss ich wirklich so kleine Schritte machen? Ich fühle mich so gebremst...
Dr. T. D. Dommer erwidert: Eine wichtige Idee hinter testgetriebener Entwicklung ist, die vollständige Kontrolle über das Programmiergeschehen zu behalten: Als Entwickler sollte ich immer wissen, ob der nächste Testlauf fehlschlagen wird oder nicht, und was ich tun muss, um einen fehlschlagenden Test wieder „grün“ zu machen. Am besten lässt sich diese Idee durchhalten, wenn ich in ganz kleinen Schritten vorgehe. In einer Minute kann ich nur Chaos für eine Minute anrichten – und dementsprechend schnell auch wieder beseitigen.
Die meisten TDD-Anfänger tendieren dazu, ihre Schritte – oft gleichbedeutend mit der Größe und Komplexität des neuesten Testfalls – stetig zu vergrößern, um schneller zu werden. Dies ist auch o.k., wenn man die Schrittweite wieder entsprechend reduziert, sobald die Kontrolle verloren geht: wenn z. B. 10 Minuten statt geschätzter zwei vergehen, bevor man alle Tests am Laufen hat. So pendelt sich die optimale Schrittweite langsam ein; erfahrene TDDler berichten meist von Mikroiterationen zwischen 2 und 5 Minuten Länge. Die Gefahr für den Test-First-Neuling ist, dass er es nicht bemerkt, wie ihm langsam die Kontrolle entgleitet und wie das geordnete Vorgehen immer mehr zu einem Stochern im Code verkommt. (O-Ton: „Vielleicht läuft der Test, wenn ich hier '<=' statt '<' benutze“.) Erwischt man sich bei einem solchen Vielleicht-Gedanken, ist die Zeit für Schrittweitenkürzung gekommen. Mein Motto lautet daher: Hier ist kürzer auf jeden Fall besser!
Ein anderer Aspekt ist die gerade am Anfang subjektiv wahrgenommene Verlangsamung. Diese rührt daher, dass die Zeit für einen Design-Test-Code-Refactor-Zyklus tatsächlich länger ist, als wenn wir lediglich den im Kopf roh vorhandenen Code hinschreiben. Dass wir jedoch durch die höhere Kontrolle die Anzahl der Verbesserungsdurchgänge reduzieren, merkt man erst nach einiger Weile. TDD sollte uns tatsächlich schon von Beginn eines Projekts an schneller machen – sobald wir die Technik beherrschen – nicht erst mittelfristig durch niedrigere Fehlerraten.




