Testgetriebene Entwicklung (TDD)
Baue Features und behebe Fehler in vertikalen Scheiben (eine nach der anderen), wobei Tests als Feedback-Schleife dienen.
Kernprinzip
Tests verifizieren Verhalten über öffentliche Schnittstellen, nicht über Implementierungsdetails. Wenn du refaktorierst und der Test bricht, ohne dass sich das Verhalten ändert, war der Test falsch.
Anti-Pattern: Horizontale Schnitte
Schreibe nicht zuerst alle Tests und dann die gesamte Implementierung. Schreibe einen Test, lass ihn bestehen, wiederhole.
Falsch: ROT test1, test2, test3 -> GRÜN impl1, impl2, impl3
Richtig: ROT test1 -> GRÜN impl1 -> ROT test2 -> GRÜN impl2 -> ...
Arbeitsablauf
1. Planen
- Bestätige die Schnittstellenänderungen mit dem Benutzer.
- Bestätige, welche Verhaltensweisen zu testen sind. Du kannst nicht alles testen.
- Liste die Verhaltensweisen als beobachtbare Ergebnisse auf, nicht als Implementierungsschritte.
- Hole die Zustimmung des Benutzers ein, bevor du Code schreibst.
2. Tracer Bullet
Schreibe einen Test für ein Verhalten. Beobachte, wie er fehlschlägt. Schreibe den minimalen Code, um ihn bestehen zu lassen.
3. Inkrementelle Schleife
Für jedes verbleibende Verhalten:
- Schreibe den nächsten Test.
- Lass ihn mit minimalem Code bestehen.
- Antizipiere keine zukünftigen Tests.
4. Refaktorieren
Nachdem alle Tests bestanden wurden:
- Entferne Doppelungen.
- Vertiefe Module: kleines Interface, tiefe Implementierung.
- Führe nach jedem Refaktorisierungsschritt die Tests erneut aus.
Refaktoriere niemals, solange Tests fehlschlagen (ROT).
Checkliste pro Zyklus
- Test beschreibt Verhalten, nicht Implementierung.
- Test verwendet die öffentliche Schnittstelle.
- Test würde einer internen Refaktorisierung standhalten.
- Code ist minimal für diesen Test.
- Keine spekulativen Features hinzugefügt.
Regeln
- Schreibe Tests vor der Implementierung für neues Verhalten.
- Verwende Typannotationen und klare Namen.
- Halte Funktionen klein und auf eine Aufgabe beschränkt.
- Scheitere frühzeitig mit klaren Fehlermeldungen.