TDD für Architekten

Zielgruppe: Architekt:innen und technische Leads, die Systemstruktur, Schnittstellen und Qualitätsziele verantworten. Voraussetzung: Einführung in TDD.

TDD wird oft als reine Entwicklerpraxis dargestellt ("schreib den Test zuerst"). Auf Architekturebene ist die interessantere Frage: welche Struktur muss ein System haben, damit TDD überhaupt praktikabel ist — und was verrät es über ein bestehendes Design, wenn TDD sich schwer anfühlt?

Testability als Architekturtreiber

Ein Test, der vor der Implementierung entsteht, kann sich nicht an eine bestehende Klassenstruktur "anschmiegen" — er zwingt dazu, die Schnittstelle so zu entwerfen, dass sie isoliert aufrufbar ist. Das hat in diesem Projekt konkrete strukturelle Konsequenzen:

Der Kausalpfeil zeigt in diese Richtung: nicht "wir haben Hexagonal Architecture gewählt und schreiben deshalb Tests", sondern "wir wollen jeden Anwendungsfall in Millisekunden isoliert testen können, und das erzwingt fast zwangsläufig Ports-und-Adapter" (siehe ADR-0002).

Ein schwerer Test ist ein Architektur-Symptom, kein Test-Problem

Wenn ein Test für einen Anwendungsfall fünf Mocks braucht, drei Setup-Zeilen für unrelated Daten enthält oder eine tiefe Objektgraph-Konstruktion erfordert, ist die naheliegende Reaktion "der Test ist zu kompliziert, ich schreibe weniger Tests". Die produktivere Lesart: die getestete Klasse hat zu viele Verantwortlichkeiten oder zu viele Abhängigkeiten (Verletzung des Single-Responsibility-Prinzips). TDD macht dieses Symptom sichtbar, bevor der Code in Produktion ist — ein nachträglich geschriebener Test hätte denselben Befund erst nach dem Fakt geliefert, wenn eine Umstrukturierung deutlich teurer ist.

Outside-In vs. Inside-Out TDD

Zwei verbreitete Strategien, in welcher Reihenfolge Schichten getrieben werden:

Dieses Projekt mischt beide bewusst je nach Use-Case-Charakter — dokumentiert jeweils im TDD-Katalog.

Testpyramide im Microservice-Zuschnitt

                    ▲
                   /E2E\            wenige, langsam, hohe Aussagekraft ueber den ganzen Fluss
                  /-----\
                 /Contract\         pro Service-Paar (Event-Schema-Kompatibilitaet)
                /---------\
               /Integration\        Testcontainers: Persistenz, Kafka-Konsumenten
              /-------------\
             / Application/  \      Use-Case-Tests, Ports gemockt
            /   Web-Slice     \
           /-------------------\
          /   Domain-Unit-Tests  \  keine Spring-Context, Millisekunden, die meisten Tests
         /-------------------------\

Details und Werkzeuge pro Ebene: siehe Teststrategie. Aus Architektursicht ist die Kernaussage: die Basis muss die breiteste sein. Ein System, in dem die meisten Tests @SpringBootTest-Integrationstests sind, hat in der Regel eine Domain, die zu eng mit Infrastruktur verwoben ist, um isoliert testbar zu sein — ein Architektur-Befund, keine reine Test-Stil-Frage.

Bezug zu ATDD/BDD

Dieses Projekt verwendet kein separates BDD-Werkzeug (kein Cucumber/Gherkin) — die deutschen, verhaltensbeschreibenden Testmethodennamen (siehe TDD für Entwickler) übernehmen dieselbe Funktion: lesbare Spezifikation direkt im Code, ohne zusätzliche Übersetzungsebene. Acceptance-Test-Driven Development (ATDD) — Abnahmekriterien eines Use-Case als ausführbaren Test formulieren, bevor die Implementierung beginnt — findet in diesem Projekt auf Ebene der Web-Slice-/Application-Tests statt: der erste Test eines neuen Use-Case ist typischerweise bereits eine grobe Abnahmebedingung ("Konto mit gültigen Daten eröffnen liefert 201 und eine IBAN").

Architekturtests als ausführbare ADRs

Die ArchUnit-Regeln in architecture-tests (z. B. CommonDomainPurityTest) sind eine Sonderform von TDD: Sie werden test-first geschrieben, um eine Architekturentscheidung explizit und dauerhaft durchsetzbar zu machen — sind aber oft schon beim ersten Ausführen grün, weil die Regel bislang nicht verletzt wurde (anders als ein normaler Produktionscode-Test, der vor der Implementierung zwangsläufig rot ist). Ihr Wert zeigt sich später: Wenn ein Refactoring-Schritt (dritte Phase des TDD-Zyklus!) versehentlich eine Schichtgrenze verletzt, schlägt die Architekturregel fehl — noch bevor ein Reviewer es manuell bemerken müsste. Man kann sie daher als ausführbare, versionierte ADRs lesen: Die zugehörige ADR erklärt das Warum, die ArchUnit-Regel erzwingt das Dass.

Wann NICHT strikt TDD?

TDD ist kein Dogma für jede Codezeile. Fälle, in denen dieses Projekt bewusst davon abweicht (siehe auch Einführung in TDD, Abschnitt "Was wird NICHT per TDD getestet"):

Architektonisch wichtig ist, diese Ausnahmen bewusst und benannt zu halten, statt TDD schleichend "wenn's grad passt" aufzugeben — sonst verliert das Sicherheitsnetz seinen Wert genau dort, wo Komplexität am größten ist.

⌂ Cockpit