Was ist testgetriebene Entwicklung?

Nutze die TDD-Methodik und die vorgegebene Testsuite, um Übungen zu lösen


Testgetriebene Entwicklung (manchmal auch Test-First Development oder Test-Driven Design genannt) bedeutet, die Unit-Tests zuerst zu schreiben, bevor du auch nur eine Zeile Implementierungscode schreibst.

Bei Exercism sind die Tests die Anforderungen!

Alle Übungsaufgaben, an denen du arbeitest (also diejenigen, die dir kein neues Konzept vermitteln), enthalten eine Anleitung, die in allgemeinen Worten beschreibt, was du tun sollst. Das ist Absicht: Diese Anleitungen gehen nicht auf die implementationsspezifischen Details der einzelnen Programmiersprachen ein, weil sie von allen über 70 Sprach-Tracks von Exercism geteilt werden. Manche Sprach-Tracks hängen für dich weitere, genauere Details an, aber nicht alle.

Wenn du mit einer Übungsaufgabe beginnst, lies die Anleitung aufmerksam durch. Sie gibt dir einen groben Überblick darüber, wie du eine Lösung umsetzt. Um die vollständigen und genauen Anforderungen zu verstehen, musst du aber die Tests lesen:

  • Muss das Ergebnis eine bestimmte Art von Datenstruktur sein?
  • Muss das Ergebnis in einer bestimmten Reihenfolge sortiert sein?
  • Wie sollst du mit Ausnahmen umgehen? Und so weiter.

Du hast eine Übung gelöst, wenn alle bereitgestellten Tests laufen und bestehen. Anders gesagt: Deine Lösung ist nicht bloß eine Interpretation der Anleitung, die „richtig aussieht", sondern ein Programm, das die gegebenen Tests erfüllt. Die Tests stellen die vollständigen Anforderungen an die Übung dar.

Wie setzt Exercism TDD um?

Wir haben die Arbeit übernommen und eine Unit-Test-Suite für dich geschrieben. Dein Ziel ist eine Lösung, die gerade genug Code enthält, damit alle diese Unit-Tests bestehen.

Denk daran: Der TDD-Ansatz hilft dir, zur Lösung zu kommen, aber du musst dort nicht stehen bleiben. Wenn du deine Lösung über die Anforderungen hinaus erweitern möchtest, nur zu. Wenn du dich dafür entscheidest, mit einem Mentor oder einer Mentorin zu arbeiten (und das empfehlen wir dir, sobald die Tests bestehen), kann er oder sie dir helfen, deine erste Implementierung zu refaktorieren und zu verfeinern, oder dir sogar neue Unit-Tests vorschlagen.

Arbeiten im Online-Editor

Wenn du im Code-Editor auf der Website von Exercism arbeitest, kannst du die Tests lesen, aber nicht bearbeiten. Alle Tests werden bei jedem Durchlauf ausgeführt, unabhängig von etwaigen „skip"-Mechanismen, die in der Testdatei vermerkt sind.

Wenn mehrere Tests fehlschlagen, zeigt die Website zunächst nur das Ergebnis des ersten Fehlers an. Du kannst auch auf andere Fehler klicken, um sie aufzuklappen! Manchmal ist das erste Ergebnis nicht das aufschlussreichste.

Lass dich von einer großen Zahl fehlschlagender Tests nicht entmutigen. Konzentriere dich darauf, sie einen nach dem anderen zum Bestehen zu bringen.

Lokales Arbeiten

Viele Tracks verwenden „übersprungene" Tests in ihren Testdateien. Anfangs ist nur der erste Test „aktiv", die übrigen sind inaktiv (wie das genau passiert, hängt vom Track ab). Wenn du die Test-Suite in deiner Umgebung ausführst, läuft nur der erste Test. Wir machen das, um dich zu diesem Workflow zu ermutigen:

  1. Bevor du neuen Code hinzufügst, führe die Test-Suite aus: Du solltest einen fehlschlagenden Test sehen.
  2. Füge gerade genug Code hinzu, damit der Test besteht.
  3. Führe die Test-Suite aus.
  4. Wenn der Test weiterhin fehlschlägt, wiederhole Schritt 2.
  5. Sobald der Test besteht, refaktorierst du deinen Code nach Belieben und stellst sicher, dass alle aktiven Tests weiterhin bestehen. Refactoring kann zum Beispiel beinhalten:
    • doppelten Code entfernen,
    • lange Funktionen in kleinere aufteilen,
    • Kommentare hinzufügen, usw.
  6. Hebe die „Skip"-Markierung beim nächsten Test auf und wiederhole ab Schritt 1.

Wiederhole diese Schritte, bis du alle Tests aktiviert hast. Sobald alle Tests bestehen: Herzlichen Glückwunsch, du hast die Übung gelöst!

Wie genau die „Skip"-Markierung bei Tests entfernt (oder Tests aktiviert) wird, hängt vom Track ab. Bei manchen Tracks heißt das, eine Annotation auszukommentieren oder zu entfernen. Bei manchen Tracks heißt das, ein Attribut von wahr auf falsch zu ändern. Nimm dir die Zeit, die Dokumentation für deinen Track zu lesen; dort werden diese Details erklärt.

Bei Tracks, die die Tests nicht überspringen, kann dieser Workflow so einfach sein wie: Tests auskommentieren und einen nach dem anderen wieder einkommentieren.

Warum testgetriebene Entwicklung sinnvoll ist

Auch wenn es wie „das Pferd von hinten aufzäumen" wirken mag, gibt es mehrere gute Gründe, die Unit-Tests zu schreiben, bevor du den Implementierungscode schreibst.

  1. Design. Es zwingt dich, zuerst über die Schnittstelle deines Programms nachzudenken (darüber, wie es seine Funktionalität nach außen bereitstellt), statt sofort damit loszulegen, wie du den Code umsetzt. Eine gut entworfene (und testbare!) Schnittstelle ist oft wichtiger als eine effiziente Implementierung.

  2. Disziplin. Tests zu schreiben wird oft als lästige Pflicht oder als Nachgedanke betrachtet; die Tests zuerst zu schreiben stellt sicher, dass du am Ende des Tages genug Unit-Tests hast, um den Großteil oder die gesamte Funktionalität deines Codes abzudecken (statt es womöglich nie zu schaffen).

  3. Weniger Arbeit. Wenn du einen engen Zyklus fährst: einen Test schreiben, dann den Code, der diesen Test umsetzt, dann den nächsten Test, wächst dein Code organisch. Das führt oft (aber nicht immer) zu weniger verschwendeter Mühe; am Ende schreibst du den ganzen Code, den du brauchst, und keinen, den du nicht brauchst.

Weiterführende Literatur