Einleitung: Warum TDD keine Religion, sondern ein Rettungsanker ist
\n\nStellen Sie sich vor, Sie reparieren die Verkabelung in einem alten Haus. Sie schalten den Hauptschalter aus, haben aber trotzdem Angst, Ihre Hände in den Sicherungskasten zu stecken. Ungefähr so fühlt sich ein Entwickler, der Änderungen an einem Projekt ohne Tests vornimmt. Besonders in Go – einer Sprache, in der statische Typisierung ein falsches Sicherheitsgefühl vermittelt.
\n\nTestgetriebene Entwicklung (TDD) in Go ist kein modischer Trend und kein sektenartiges Ritual. Es ist eine Methodik, die Angst vor Refactoring in Zuversicht verwandelt. Laut einer Studie von IBM weisen Projekte mit TDD 40% weniger Fehler auf. Und in Go, wo der Compiler bereits die Hälfte der Fehler abfängt, erledigt TDD die restlichen 50%.
\n\nIn diesem Artikel halten wir keine Vorträge. Wir nehmen eine reale Aufgabe: Wir schreiben einen kleinen HTTP-Dienst zum Kürzen von Links. Und wir gehen den gesamten TDD-Weg – vom roten Test über den grünen bis zum Refactoring. Los geht's!
\n\nWas ist TDD eigentlich?
\n\nWenn Sie schon von Red-Green-Refactor gehört haben – dann sind Sie bereits im Thema. Wenn nicht – merken Sie sich drei einfache Schritte:
\n\n- \n
- Red – wir schreiben einen Test, der bewusst fehlschlägt (weil die Funktionalität noch nicht existiert). \n
- Green – wir schreiben minimalen Code, damit der Test besteht. Nicht ideal, sondern einfach funktionierend. \n
- Refactor – wir verbessern den Code, ohne sein Verhalten zu ändern. Die Tests sind unsere Absicherung. \n
In Go ist dieser Zyklus dank des integrierten Pakets testing besonders angenehm. Sie müssen kein jest oder pytest installieren – alles ist bereits in der Standardbibliothek enthalten. Aber viele Anfänger ignorieren Tests, weil sie denken, Go sei ja sowieso „sicher“. Und das ist ein Fehler.
Warum funktioniert TDD in Go besser als in anderen Sprachen?
\n\nDie Go-Community liebt Einfachheit. TDD wird hier nicht zur Bürokratie mit Mocks und Stubs. Stattdessen schreiben Sie tabellenbasierte Tests (table-driven tests) – kompakt, lesbar, verständlich. Ein Testfall – eine Zeile. Und ja, Go-Tests sind schnell. Millisekunden für hunderte Fälle sind normal.
\n\nÜbrigens wurde im offiziellen Go-Blog mehrfach betont: „Tests sind Dokumentation“. Wenn Ihr Test wie eine Spezifikation gelesen werden kann – machen Sie alles richtig.
\n\nUmgebung einrichten: Was Sie für den Start brauchen
\n\nIch gehe davon aus, dass Go bei Ihnen bereits installiert ist. Falls nicht – brew install go oder apt install golang-go. Überprüfen Sie die Version: go version. Für den Artikel reicht Go 1.21+.
Wir erstellen das Projekt:
\n\nmkdir url-shortener-tdd\ncd url-shortener-tdd\ngo mod init url-shortener\n\nFertig. Keine Frameworks – nur die Standardbibliothek und testgetriebene Entwicklung in Go.
\n\nDen ersten Test schreiben: Red
\n\nAngenommen, wir wollen eine Funktion Shorten(url string) string, die eine lange URL in einen kurzen Hash verwandelt. Sie existiert noch nicht – und das ist großartig. Wir schreiben den Test:
// shortener_test.go\npackage main\n\nimport "testing"\n\nfunc TestShorten(t *testing.T) {\n url := "https://pythonlib.ru/very/long/path?with=params&and=stuff"\n result := Shorten(url)\n\n if len(result) == 0 {\n t.Error("Shorten hat einen leeren String zurückgegeben")\n }\n\n if len(result) > 10 {\n t.Errorf("Erwartete einen kurzen Hash, habe %d Zeichen erhalten", len(result))\n }\n}\n\nStarten: go test -v. Wir sehen rot (technisch gesehen einen Kompilierungsfehler). Die Funktion Shorten existiert nicht. Perfekt, wir sind in der Red-Phase.
Minimaler Code: Green
\n\nJetzt schreiben wir genau so viel, dass der Test besteht. Keine Kryptographie, nur ein Hash:
\n\n// shortener.go\npackage main\n\nimport (\n "crypto/sha256"\n "fmt"\n)\n\nfunc Shorten(url string) string {\n hash := sha256.Sum256([]byte(url))\n return fmt.Sprintf("%x", hash[:4]) // nimm die ersten 4 Bytes\n}\n\nStarten Sie den Test erneut. Grün? Hervorragend. Aber der Code ist schrecklich – der Hash ist kollisionsanfällig, und wir prüfen nicht einmal, ob