Schreibe zuerst den Test, lass ihn das Design treiben und baue mit jedem Tastendruck Vertrauen auf.
Test-Driven Development ist einfach zu beschreiben und schwer zu meistern:
Das war's. Drei Schritte, hunderte Male am Tag wiederholt.
Die Reihenfolge ist wichtig. Du schreibst den Test zuerst, bevor irgendein Produktionscode existiert. Das fühlt sich anfangs verkehrt an. Aber es verändert alles:
TDD ist Design
TDD ist eine Designtechnik, die als Testtechnik getarnt ist. Die Tests sind nicht der Punkt – das Denken, das sie hervorbringt, ist es.
Der schwierigste Teil von TDD ist zu lernen, Tests für Code zu schreiben, der noch nicht existiert. So geht's:
Beginne mit dem Interface, nicht mit der Implementierung. Wie sollte der Code aussehen, wenn er fertig ist? Schreibe einen Test, der ihn so verwendet.
Fange klein an. Versuche nicht, alles auf einmal zu testen. Teste zuerst den einfachsten möglichen Fall.
Lass ihn aus dem richtigen Grund fehlschlagen. Der Test sollte fehlschlagen, weil die Funktionalität nicht existiert, nicht weil du einen Syntaxfehler gemacht hast.
Verwende Testnamen als Dokumentation. Der Testname sollte beschreiben, welches Verhalten du testest: „gibt leere Liste zurück, wenn keine Elemente dem Filter entsprechen", nicht „test1".
Den Test zuerst zu schreiben zwingt dich, über Folgendes nachzudenken:
Das sind Designfragen. Indem du sie beantwortest, bevor du den Code schreibst, triffst du bessere Designentscheidungen.
Brauche eine Funktion zur Berechnung der Versandkosten. Schreibe einen Test: „Versand nach Kalifornien mit 50-$-Bestellung kostet 5 $". Dann schreibe gerade genug Code, um ihn zu bestehen. Dann teste den nächsten Fall.
Schreibe die gesamte Versandkostenberechnung mit allen Grenzfällen. Versuche dann, Tests zu schreiben. Stelle fest, dass der Code schwer zu testen ist, weil er nicht für Testbarkeit designt wurde. Schreibe unordentliche Tests oder überspringe das Testen.
Sobald du einen fehlschlagenden Test hast, lass ihn bestehen. Aber hier ist die Disziplin: Schreibe den minimalen Code, um den Test zu bestehen, nicht mehr.
Das bedeutet:
Das klingt lächerlich. „Einfach 5 zurückgeben?" Ja, wenn das den Test bestehen lässt. Dann schreibe einen weiteren Test, der dich zwingt, echte Berechnungen durchzuführen.
Warum? Weil:
Die Magie passiert, wenn du triangulierst. Erster Test: gib 5 zurück. Zweiter Test (andere Eingabe): jetzt musst du berechnen. Dritter Test: jetzt musst du Grenzfälle behandeln. Jeder Test treibt dich zu einer echten Implementierung.
Wenn du den Test bestehen lassen kannst, indem du „return 5" schreibst, schreibe „return 5". Dann schreibe einen weiteren Test, der es kaputt macht. Lass die Tests dich zu echtem Code treisen.
Nachdem der Test besteht, räume auf. Das ist nicht optional.
Der Refactoring-Schritt ist der Ort, an dem du:
Der Schlüssel: Halte die Tests während des gesamten Vorgangs grün. Refactore in winzigen Schritten und führe Tests nach jeder Änderung aus. Wenn Tests fehlschlagen, weißt du genau, was kaputt gegangen ist.
Hier zahlt sich TDD aus. Ohne Tests ist Refactoring beängstigend – du könntest etwas kaputt machen. Mit Tests ist Refactoring Routine – du wirst sofort wissen, wenn du etwas kaputt machst.
Den Refactoring-Schritt zu überspringen führt zu dem, was Kent Beck „Quick-Green-Ausreden" nennt. Der Code funktioniert, aber er ist unordentlich. Das Durcheinander häuft sich an. Bald ist die Codebasis schwer zu bearbeiten, und du hast den Vorteil von TDD verloren.
Mythos: TDD ist langsamer. Realität: TDD scheint anfangs langsamer, weil du mehr Code schreibst. Aber du verbringst weniger Zeit mit Debugging, weniger Zeit im Debugger, weniger Zeit mit der Behebung von Produktionsfehlern. Über die Lebensdauer der Codebasis ist TDD schneller.
Mythos: TDD führt zu Übertesten. Realität: TDD führt zu genau den Tests, die du brauchst – nicht mehr, nicht weniger. Du testest, was du baust. Test-After führt oft zu fehlenden Tests (du vergisst Grenzfälle) oder redundanten Tests (du testest dasselbe auf mehrere Arten).
Mythos: TDD funktioniert nicht für [meine Domäne]. Realität: TDD funktioniert für jeden Code, der getestet werden kann. Wenn dein Code nicht getestet werden kann, ist das ein Designproblem. TDD zwingt dich, testbaren Code zu schreiben, was besserer Code ist.
Mythos: Wir haben keine Zeit für TDD. Realität: Du hast keine Zeit, es nicht zu tun. Bugs sind teuer. Debugging ist teuer. Produktionsvorfälle sind teuer. TDD ist eine Investition, die sich auszahlt.
Nicht verhandelbar
In XP ist TDD kein Nice-to-have. Es ist eine nicht verhandelbare Praktik. Ohne Tests wird jede andere Praktik schwieriger oder unmöglich.