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.
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:
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.
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.
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.
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:
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.
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.
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.
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).
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.