Test Driven Development: Red-Green-Refactor
Test Driven Development, kurz TDD, ist eine Entwicklungspraxis, bei der Tests vor der Produktivcode geschrieben werden. Der bekannte Red-Green-Refactor-Zyklus zwingt Entwickler, sich vor der Implementierung über das gewünschte Verhalten klar zu werden. Das Ergebnis ist oft besserer, testbarer und fokussierter Code.
In a Nutshell
- TDD schreibt Tests vor dem Produktivcode.
- Der Zyklus besteht aus Red, Green und Refactor.
- Red: Test schreiben, der fehlschlägt.
- Green: Minimaler Code, damit der Test besteht.
- Refactor: Code verbessern, ohne das Verhalten zu ändern.
- TDD fördert kleine Schritte, klare Anforderungen und testbaren Code.
Kompakte Fachbeschreibung
TDD kehrt die traditionelle Reihenfolge um. Statt zuerst Code zu schreiben und später Tests zu ergänzen, beginnt der Entwickler mit einem fehlschlagenden Test. Dieser Test beschreibt das gewünschte Verhalten. Danach wird der kleinste mögliche Code geschrieben, der den Test erfüllt. Im letzten Schritt wird der Code bereinigt, ohne die Tests zu brechen.
Der Red-Green-Refactor Zyklus
Red
Schreibe einen Test für eine noch nicht implementierte Funktion. Führe den Test aus. Er muss fehlschlagen, sonst ist der Test nicht aussagekräftig.
Green
Schreibe den minimalen Code, der benötigt wird, damit der Test besteht. Eleganz spielt in diesem Schritt noch keine Rolle, das Ziel ist ein grüner Test.
Refactor
Bereinige den Code, entferne Duplikate, verbessere Namen und Struktur. Alle Tests müssen weiterhin grün bleiben.
Best Practices
- Kleine Schritte: Jeder Zyklus sollte wenige Minuten dauern.
- Fokus auf Verhalten: Tests beschreiben, was die Software tun soll, nicht wie sie es intern tut.
- Kein überflüssiger Code: Schreibe nur Code, der einen Test erfüllt.
- Refactor nicht überspringen: Der dritte Schritt ist essenziell für Clean Code.
- Tests lesbar halten: Tests dokumentieren die Absicht des Codes.
Praxisbeispiel: Rabattberechnung mit TDD
import unittest
from app.pricing import calculate_discount
class TestDiscount(unittest.TestCase):
def test_no_discount_below_threshold(self):
self.assertEqual(calculate_discount(50), 0)
def test_discount_for_threshold(self):
self.assertEqual(calculate_discount(100), 10)
def test_higher_discount_for_large_amount(self):
self.assertEqual(calculate_discount(200), 20)
if __name__ == '__main__':
unittest.main()
def calculate_discount(amount):
if amount >= 200:
return 20
if amount >= 100:
return 10
return 0
Vorteile und Nachteile
Vorteile
- Klarere Anforderungen: Tests zwingen dazu, das gewünschte Verhalten zu definieren.
- Schnelles Feedback: Fehler werden sofort erkannt.
- Bessere Code-Qualität: TDD fördert kleine, fokussierte Funktionen.
- Sicherheit beim Refactoring: Tests schützen vor Regressionen.
- Lebende Dokumentation: Tests zeigen, wie die Software verwendet werden soll.
Nachteile
- Lernkurve: TDD erfordert Übung und Disziplin.
- Anfangsaufwand: Der erste Schritt kostet mehr Zeit als herkömmliches Programmieren.
- Nicht für alles geeignet: Spikes, Prototypen oder explorative Entwicklung profitieren weniger.
- Falsche Tests: Schlecht geschriebene Tests führen zu schlechtem Design.
Prüfungsrelevante Stichpunkte
- Definition und Ziel von TDD.
- Die drei Phasen Red, Green, Refactor.
- Unterschied zwischen TDD und herkömmlichem Testen.
- Vorteile und Grenzen von TDD.
- Bedeutung von kleinen Schritten und Refactoring.
Typische Prüfungsfragen (mit Kurzantwort)
-
Was ist TDD? Eine Entwicklungspraxis, bei der Tests vor dem Produktivcode geschrieben werden.
-
Welche drei Phasen hat der TDD-Zyklus? Red, Green, Refactor.
-
Was passiert in der Red-Phase? Ein Test wird geschrieben, der fehlschlägt, weil die Funktion noch nicht existiert.
-
Was ist das Ziel der Green-Phase? Der kleinste Code, der den Test erfüllt.
-
Was ist ein Vorteil von TDD? Schnelles Feedback und bessere Testabdeckung durch kleine, fokussierte Schritte.
Wichtigste Quellen
- https://www.agilealliance.org/glossary/tdd/
- https://martinfowler.com/bliki/TestDrivenDevelopment.html
- https://en.wikipedia.org/wiki/Test-driven_development
Häufig gestellte Fragen
Was bedeutet Red-Green-Refactor?
Red steht für einen fehlschlagenden Test, Green für den minimalen Code, der ihn bestehen lässt, und Refactor für das Bereinigen ohne Verhaltensänderung.
Muss bei TDD jede Zeile Code getestet werden?
Nein. TDD zielt darauf ab, das Verhalten durch Tests zu definieren, nicht blind jede Zeile abzudecken. Qualität der Tests zählt mehr als Quantität.
Ist TDD nur für Unit Tests geeignet?
Traditionell beginnt TDD mit Unit Tests, lässt sich aber auch auf Integrationstests oder Akzeptanztests erweitern, beispielsweise durch ATDD.
Was ist ATDD?
Acceptance Test Driven Development erweitert TDD auf Akzeptanztests. Dabei werden Tests aus der Sicht des Nutzers oder Auftraggebers vor der Implementierung geschrieben.
Wie lange sollte ein TDD-Zyklus dauern?
Ein idealer Zyklus dauert nur wenige Minuten. Kleine Schritte ermöglichen schnelles Feedback und einfaches Refactoring.
Was passiert, wenn ich den Refactor-Schritt überspringe?
Der Code bleibt hackig und wird mit der Zeit schwerer wartbar. Refactoring ist der Schritt, der für Clean Code und nachhaltige Qualität sorgt.
Kann TDD in bestehenden Projekten eingeführt werden?
Ja, aber es erfordert oft Refactoring, um bestehenden Code testbar zu machen. Neue Funktionen und Bugfixes sind gute Startpunkte.
Ist TDD langsamer als herkömmliches Programmieren?
Am Anfang kann TDD langsamer wirken. Langfristig reduziert es jedoch Fehlerkosten und Beschleunigt Refactorings und Erweiterungen.
Was ist ein TDD-Anti-Pattern?
Ein häufiges Anti-Pattern ist das Schreiben von Tests nach der Implementierung. Auch zu detaillierte Mocks oder zu große Tests pro Zyklus sind problematisch.
Wie fördert TDD Clean Code?
TDD erzwingt testbaren Code, was meist modulareren, entkoppelteren und besser benannten Code zur Folge hat.
Was ist der Unterschied zwischen TDD und BDD?
TDD konzentriert sich auf technische Tests für den Entwickler. BDD übersetzt Anforderungen in Beispiele aus der Geschäftssprache, um Entwickler und Fachbereiche zusammenzubringen.
Welche Programmiersprachen eignen sich für TDD?
TDD ist prinzipiell sprachunabhängig. Besonders beliebt ist es in Java, Python, JavaScript, C# und Ruby, weil dort gute Test-Frameworks verfügbar sind.
Was sollte ich testen, wenn ich bei null anfange?
Beginne mit dem einfachsten, zentralen Verhalten. Beispielsweise mit dem Standardfall oder einem klaren Fehlerfall, bevor Du komplexe Randfälle abdeckst.
Wie gehe ich mit externen Abhängigkeiten bei TDD um?
Externe Abhängigkeiten werden durch Test Doubles wie Mocks, Stubs oder Fakes ersetzt, damit der Unit Test isoliert und schnell bleibt.
Was ist ein häufiger Grund für TDD-Scheitern?
Zu große Schritte, unklare Anforderungen und das Vermeiden des Refactor-Schritts führen oft dazu, dass TDD frustriert und nicht nachhaltig bleibt.
Weiter im Software Testing Lernpfad
Der nächste Artikel im Software Testing Lernpfad behandelt Behavior Driven Development — wie BDD die Kommunikation zwischen Entwicklern und Stakeholdern verbessert.



