Mehr als 12’000 Unit-Tests, alle grün. Und trotzdem tauchen die Fehler erst beim Release auf.
Das berichtet Paul Stack von Swamp, wo Agenten jede Zeile Code schreiben. In zwei aktuellen Beiträgen, Your Agent-Written Tests Aren’t Real Tests und Why Agent-Written Code Needs Product Verification, erklärt er, warum. Ich stimme ihm in fast allem zu. Und ich halte seine Schlussfolgerung für das beste Argument für Spec-Driven Development, das ich dieses Jahr gelesen habe.
In diesem Beitrag erkläre ich seinen Hauptpunkt, zeige, wie der AI Unified Process ihn bereits beantwortet, und was ich in meinen eigenen Plugins geändert habe.
Dasselbe Missverständnis, zweimal geschrieben
Wenn ein Agent eine Funktion schreibt und danach den Unit-Test dazu, stammen beide aus demselben Verständnis der Anforderung. Hat der Agent die Anforderung falsch verstanden, ist der Test auf dieselbe Weise falsch. Der Code besteht den Test. Der Build ist grün. Das Produkt ist trotzdem falsch.
Es kommt noch schlimmer. Wenn ein Test in der Agenten-Schleife fehlschlägt, ist der schnellste Weg zu Grün, den Test zu ändern. Für den Agenten ist ein Test einfach eine weitere Datei, die er bearbeiten kann. Bei Swamp lief die UAT-Suite rund 2’000 Mal und fand in 80 Läufen echte Fehler. Alle diese Fehler hatten die komplette Unit-Test-Suite bestanden.
Stack verweist auch auf Forschung. Agenten aufzufordern, Tests zu schreiben, half ihnen nicht, mehr Issues zu lösen. Die meisten Test-Patches von Agenten haben schwache Assertions oder gar kein echtes Orakel.
Was sind diese Tests also? Stack sagt, sie sind eine Spezifikation, keine Verifikation. Sie sind eine nützliche Landkarte für den nächsten Agenten. Sie zeigen, was der Code tun soll. Aber sie sind kein Beweis, dass der Code richtig ist.
Es geht nicht um die Teststufe
Eine verbreitete Antwort ist gerade: die Testpyramide umdrehen. Weniger Unit-Tests und mehr End-to-End-Tests schreiben. Stack sagt, das reicht nicht, und ich stimme zu. Wenn der Agent die End-to-End-Tests aus seinem eigenen Verständnis schreibt, bestätigen auch sie das Falsche. Sie sehen nur überzeugender aus.
Der Schlüsselsatz seines zweiten Beitrags lautet: Unabhängigkeit ist eine Eigenschaft davon, woher die Erwartungen kommen und wer sie ändern kann. Nicht der Teststufe.
Daraus ergeben sich zwei einfache Regeln:
- Die Erwartungen müssen von ausserhalb der Implementierungsschleife kommen. Aus einer Produktdefinition, von Fachexperten, aus einer Spezifikation, die ein Mensch freigegeben hat.
- Die Erwartungen müssen geschützt sein. Wenn der Agent einen fehlschlagenden Test so lange ändern kann, bis er besteht, ist der Test als Prüfung wertlos.
Stack macht auch eine nützliche Unterscheidung. Der Agent darf die Testmechanik pflegen: Selektoren, Fixtures, Setup. Das ist Routinearbeit, und Agenten machen sie gut. Aber eine Änderung an einer Assertion, an einem erwarteten Wert oder an der Liste der abgedeckten Funktionen braucht ein Review ausserhalb der Schleife.
Unit-Tests verschwinden nicht. Sie sind weiterhin wertvoll, wo die Regel ausserhalb des Codes definiert ist: eine Preisregel, ein Berechtigungsmodell, eine regulatorische Prüfung. Die Frage ist immer dieselbe. Prüft der Test eine Regel, die jemand anderes definiert hat, oder wiederholt er nur, was die Implementierung ohnehin tut?
Wo der AI Unified Process das Orakel platziert
Als ich Stacks Beiträge las, erkannte ich darin den Grund, warum ich den AI Unified Process um Anforderungen und Use Cases herum gebaut habe und nicht um Code.
Im AI Unified Process stehen die Erwartungen in der Spezifikation, bevor es Code gibt:
- Use-Case-Spezifikationen beschreiben das Hauptszenario, die alternativen Abläufe, die Nachbedingungen und die Geschäftsregeln. Ein Mensch prüft und genehmigt sie.
- Testfälle verketten mehrere Use Cases zu einer User Journey. Sie enthalten konkrete Testdaten mit literalen Werten und Validierungen, die du im UI beobachten kannst. Platzhalter wie «ein gültiger Kunde» sind nicht erlaubt, weil man sie nicht automatisieren kann.
- Implementierung und Tests sind getrennte Schritte. Der Implementierungs-Skill schreibt keine Tests. Die Test-Skills leiten die Tests aus dem Use Case oder Testfall ab. Die Playwright-Tests sind Black-Box-Tests gegen die laufende Anwendung.
- Jeder Test verweist auf die Spec. Eine
@UseCase-Annotation nennt den Use Case, das Szenario und die Geschäftsregeln, die eine Testmethode abdeckt. - Der Coverage-Check ist unabhängig.
/coverage-checkläuft in einem separaten Sub-Agenten, der nur lesen darf. Er prüft Code und Tests gegen die Spezifikation, nie gegen eine aus dem Code rekonstruierte Spezifikation. Eine@UseCase-Annotation allein gilt als Behauptung, nicht als Beleg. Der Prüfer liest den Testcode.
Die Frage «Wem gehört das Orakel?» hat also eine klare Antwort:
| Artefakt | Gehört | Der Agent darf |
|---|---|---|
| Anforderungen, Use-Case-Specs, Geschäftsregeln | Fachbereich und Analysten, von einem Menschen freigegeben | Änderungen vorschlagen, nie entscheiden |
| Testfälle (TC) mit Testdaten und Validierungen | Fachbereich und Tester | Änderungen vorschlagen, nie entscheiden |
| Testmechanik (Selektoren, Fixtures, Setup) | dem Agenten | frei ändern |
| Assertions und erwartete Werte | der Spezifikation | nur ändern, wenn sich die Spec ändert |
| Produktivcode | dem Agenten | frei ändern |
Das ist die Shift-Left-Idee, angewendet auf die Verifikation. Das Orakel existiert vor dem Code, und es gehört einem Menschen.
Was ich in meinen Plugins geändert habe
Die Methode stimmt, aber Stacks Beiträge haben mich meine eigenen Plugins mit neuen Augen ansehen lassen. Ich habe Lücken gefunden und die wichtigsten sofort geschlossen. Die Änderungen sind im Marketplace für alle vier Stacks verfügbar: Vaadin mit jOOQ, Angular mit JPA, Blazor mit .NET und NestJS mit Next.js.
1. Eine Regel für fehlschlagende Tests. Bisher sagten die Test-Skills dem Agenten, er solle die Tests ausführen und prüfen, dass sie bestehen. Sie sagten nicht, was zu tun ist, wenn ein Test fehlschlägt. Jetzt hat jeder Test-Skill einen Abschnitt «When a Test Fails». Die Spezifikation ist das Orakel, nicht der Code. Jeder erwartete Wert kommt aus der Spezifikation oder den Testdaten, nie aus einem Lauf des Codes. Wenn ein Test fehlschlägt, entscheidet der Agent zuerst, welche Seite falsch ist:
- Ein Problem in der Testmechanik, etwa ein Locator, ein Wait, eine Fixture oder das Setup: Der Agent korrigiert den Test.
- Ein Wert oder Ergebnis, das die Spezifikation festlegt, etwa eine Meldung, eine Anzahl, ein Status oder ein berechneter Wert: Der Code widerspricht der Spezifikation. Der Agent darf die Assertion nicht ändern, abschwächen oder löschen und den Test nicht deaktivieren. Der Test bleibt rot. Der Agent meldet die Regel, den erwarteten und den tatsächlichen Wert. Welche Seite falsch ist, entscheide ich, nicht der Agent.
Die Skills nennen sogar die typischen Tricks: isGreaterThan(0) statt der echten Anzahl, isNotEmpty(), ein Teilvergleich statt der vollständigen Meldung, @Disabled oder .skip.
2. Die Implementierung fasst das Orakel nicht an. /implement bearbeitet keinen bestehenden Test und nichts unter docs/ mehr. Wenn ein Test gegen den neuen Code fehlschlägt oder eine Spezifikation falsch aussieht, landet das unter Open questions im Bericht. Der Agent darf die beiden nicht in Einklang bringen, indem er eines davon ändert.
3. Bessere Beispiele. Agenten kopieren die Referenztests, also müssen diese das Richtige zeigen. Die alten Vorlagen verwendeten isGreaterThan(0). Jetzt prüfen sie die exakten Werte aus den Testdaten, zum Beispiel genau 100 Personen, und zitieren die Spezifikation. Die Playwright-Vorlage folgt jetzt der Benennung des Use Case.
4. Formen aus dem Code, Werte aus der Spec. Der Hilla-Test-Skill liest den generierten Client, um Methodennamen und DTO-Strukturen zu kennen. Das ist Mechanik. Die erwarteten Werte kommen weiterhin nur aus der Spezifikation.
5. Reverse Engineering erzeugt Entwürfe. Wenn /reverse-engineer Use Cases aus bestehendem Code gewinnt, setzt es den Status jetzt immer auf Draft. Eine so gewonnene Spezifikation beschreibt, was der Code tut, nicht was er tun soll. Hat der Code einen Fehler, steht dieser Fehler jetzt als gefordertes Verhalten da. Deshalb muss ein Mensch den Use Case prüfen und freigeben, bevor daraus ein Test abgeleitet wird.
Wie es weitergeht
Einige Ideen brauchen mehr Arbeit, und ich komme darauf zurück:
- Technischer Schutz. Die Regeln oben sind Anweisungen an den Agenten. Ein Hook oder ein CI-Check, der fehlschlägt, wenn sich eine Assertion ohne Spec-Änderung ändert, würde daraus harte Regeln machen.
- Beispiele für jede Geschäftsregel. Eine kleine Tabelle pro Regel mit Eingabe, erwartetem Ergebnis und Grenzwerten.
/spec-reviewkönnte warnen, wenn eine Regel keine hat. - Ein Ablauf für Fehler. Wenn ein Fehler durchrutscht, zuerst die Spec korrigieren: ein neuer alternativer Ablauf, eine Geschäftsregel oder ein Testfall. Dann der Regressionstest. Dann der Code.
- Tests nur aus der Spec. Die Tests in einer separaten Session schreiben, die die Spezifikation sieht, aber nicht die Implementierung.
- Unit- und Architekturtests, wo sie hingehören. Unit-Tests auf Regelebene für Preis- oder Berechtigungsregeln und ArchUnit-Tests für Regeln aus dem Software-Architektur-Dokument.
Fazit
Agenten haben Code billig gemacht. Sie haben auch End-to-End-Tests billiger im Unterhalt gemacht und Fehler schneller behebbar. Aber gute Erwartungen haben sie nicht billig gemacht. Jemand muss immer noch entscheiden, was das Produkt tun muss, und dieser Jemand sollte nicht der Agent sein, der den Code schreibt.
Mehr Tests lösen das nicht. Mehr Coverage löst das nicht. Was es löst, ist eine Spezifikation, die einem Menschen gehört, die vor dem Code existiert und die der Agent nicht ändern kann, um auf Grün zu kommen.
Das ist der Kern von Spec-Driven Development und der Kern des AI Unified Process. Danke, Paul Stack, dass du es so klar formuliert hast. Und für den Anstoss, meine eigenen Plugins besser zu machen.
Keep IT simple.
Quellen
- Paul Stack: Your Agent-Written Tests Aren’t Real Tests, 23. September 2026
- Paul Stack: Why Agent-Written Code Needs Product Verification, 6. Oktober 2026
- AI Unified Process


