Simyl
simylflow
Kursübersicht
Modul 2: Technische Praktiken
Lektion 1 von 5
14 Min.

Test-Driven Development

Schreibe zuerst den Test, lass ihn das Design treiben und baue mit jedem Tastendruck Vertrauen auf.

1Der Rot-Grün-Refactor-Zyklus

Test-Driven Development ist einfach zu beschreiben und schwer zu meistern:

  1. Rot: Schreibe einen fehlschlagenden Test für das nächste kleine Stück Funktionalität
  2. Grün: Schreibe den minimalen Code, um den Test zu bestehen
  3. Refactor: Räume den Code auf, während die Tests grün bleiben

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:

  • Du denkst darüber nach, wie der Code verwendet wird, bevor du darüber nachdenkst, wie er implementiert wird
  • Du erhältst sofortiges Feedback, ob dein Code funktioniert
  • Du baust ein Sicherheitsnetz, das furchtlose Änderungen ermöglicht
  • Du erstellst ausführbare Dokumentation dessen, was der Code tut

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.

2Den Test zuerst schreiben

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:

  • Welche Eingaben braucht dieser Code?
  • Welche Ausgaben sollte er produzieren?
  • Was passiert in Grenzfällen?
  • Wie wird anderer Code dies aufrufen?

Das sind Designfragen. Indem du sie beantwortest, bevor du den Code schreibst, triffst du bessere Designentscheidungen.

Guter Test-First-Ansatz

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.

Test-After-Falle

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.

3Ihn bestehen lassen (auf die richtige Weise)

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:

  • Wenn eine Konstante den Test bestehen lässt, verwende eine Konstante
  • Wenn das Hartcodieren eines Rückgabewerts funktioniert, codiere ihn hart
  • Verallgemeinere nicht, bis du Tests hast, die Verallgemeinerung erfordern

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:

  • Du Funktionalität in winzigen, verifizierten Schritten aufbaust
  • Du niemals Code schreibst, den du nicht brauchst
  • Du das Design inkrementell entdeckst
  • Jede Codezeile durch einen Test gerechtfertigt ist

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.

4Der Refactoring-Schritt

Nachdem der Test besteht, räume auf. Das ist nicht optional.

Der Refactoring-Schritt ist der Ort, an dem du:

  • Duplikate entfernst (DRY: Don't Repeat Yourself)
  • Namen verbesserst (lass den Code wie Prosa lesen)
  • Logik vereinfachst (reduziere kognitive Last)
  • Reorganisierst (verschiebe Code dorthin, wo er hingehört)

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.

5TDD-Mythen entlarvt

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.

Wichtige Erkenntnisse
  • TDD folgt dem Rot-Grün-Refactor-Zyklus: fehlschlagen, bestehen, aufräumen
  • Schreibe den Test zuerst – es ist eine Designtechnik, nicht nur Testen
  • Lass Tests mit dem minimal nötigen Code bestehen, dann iteriere
  • Überspringe niemals den Refactoring-Schritt – dort wird Qualität aufgebaut
  • TDD ist langfristig schneller, obwohl es anfangs langsamer erscheint
Häufige Fehler, die es zu vermeiden gilt
  • Tests nach dem Code schreiben (du verlierst den Designvorteil)
  • Den Refactoring-Schritt überspringen (Codequalität verschlechtert sich)
  • Implementierungsdetails statt Verhalten testen
  • Zu viel Code schreiben vor dem nächsten Test

Praxisübungen