tests-and-ai-coding-tools.html
< BACK Abgenutzter Schreibtisch mit Notizbüchern, aufgeklappter Laptop mit Code und eine Tasse Tee unter kühlem Londoner Fensterlicht

Warum ich wieder Tests schreibe (KI hat mich dazu gebracht)

Anfang 2022 traf ich eine stille Entscheidung: Ich hörte auf, Unit Tests für die meisten WordPress- und Node-Projekte zu schreiben, die durch Seahawk liefen. Nicht laut. Kein Blogpost darüber. Ich hörte einfach auf. Die Begründung war schlüssig, dachte ich — wir lieferten 15 bis 20 Client-Sites pro Monat, ich hatte drei andere Entwickler im Wechsel, und die Tests, die ich schrieb, fühlten sich wie Dokumentation an, die niemand las. Manuelle QA fing die echten Bugs. Tests waren Theater.

Spulen Sie zu spät 2023. GitHub Copilot war seit etwa acht Monaten in meinem Editor. Ich hatte auch angefangen, Cursor parallel für alles Greenfield zu nutzen. Die Geschwindigkeit war wirklich bemerkenswert. Aber etwas begann zu passieren. Bugs erschienen an Stellen, die ich nicht angefasst hatte. Logik, die korrekt aussah, war in Edge Cases falsch, die ich nie hätte überprüfen sollen. Und das Schlimmste — die KI wusste nicht, dass sie falsch war. Sie schrieb den fehlerhaften Code mit der gleichen selbstbewussten Einrückung, die sie immer hat.Cursor on the side for anything greenfield. The speed was genuinely remarkable. But something started happening. Bugs were appearing in places I hadn't touched. Logic that looked correct was wrong in edge cases I'd never thought to check. And the worst part — the AI had no idea it was wrong. It wrote the broken code with the same confident indentation it always does.

Da nahm ich die Tests wieder auf.

---

Der Zeitraum, in dem ich Tests abgebrochen habe (Und warum es damals sinnvoll war)

Ehrlich gesagt? Bei einer bestimmten Art von Projekt war es richtig, Tests zu überspringen. Wenn du eine fünf-seitige Broschüren-Website in WordPress baust, PHPUnit-Tests für ein Contact-Form-Plugin zu schreiben, ist Theater. Dazu stehe ich.was the right call. If you're building a five-page brochure site in WordPress, writing PHPUnit tests for a contact form plugin is theatre. I stand by that.

Seahawks Kerngeschäft war lange Zeit genau das — hohe Volumen, relativ niedrige Komplexität, klar definierter Umfang. Ein Kunde reicht dir eine Figma-Datei, du baust sie um, du QA-st sie, du shipst sie. Die Feedback-Schleifen waren kurz. Wenn etwas kaputt ging, würdest du es innerhalb von Stunden wissen. Tests in diesem Kontext zu schreiben, ist das Developer-Äquivalent dazu, eine Post-it-Note zu laminieren.

Aber ich habe diese Lektion zu aggressiv verallgemeinert. Ich habe angefangen, alle Projekte wie Broschüren-Websites zu behandeln. Auch die mit Custom-WooCommerce-Checkout-Flows. Auch das Fintech-Dashboard, das wir Anfang 2023 für einen Kunden in Frankfurt gebaut haben — vollständige Custom-REST-API, JWT-Auth, drei verschiedene Benutzer-Berechtigungsebenen. Keine Tests. Nur „sorgfältige manuelle QA". Das war arrogant, und es hat uns getroffen.all projects like brochure sites. Even the ones with custom WooCommerce checkout flows. Even the fintech dashboard we built in early 2023 for a client in Frankfurt — full custom REST API, JWT auth, three different user permission tiers. No tests. Just "careful manual QA." That was arrogant, and it bit us.

Das Frankfurt-Projekt shipped mit einem Berechtigungs-Bug, der Editor-Level-Usern erlaubte, Admin-Level-Daten unter einer spezifischen Filterkombination abzufragen. Wir haben es erst bemerkt, als ihr internes Team sechs Wochen nach dem Launch eine Sicherheitsprüfung durchgeführt hat. Peinlich. Reparierbar. Aber genau die Art von Ding, das ein einfacher Integration-Test geflaggt hätte, bevor wir auch nur einen Pull Request gestellt hätten.

---

Was AI-Coding-Tools tatsächlich verändert haben

Hier ist das, was die meisten Leute übersehen, wenn sie über Copilot oder Cursor oder welches Modell gerade heiß ist sprechen: Der Code sieht richtig aus. Das ist das Problem.looks right. That's the problem.

Wenn ein Junior Developer fehlerhaften Code schreibt, sieht man die Unsicherheit oft darin. Seltsame Variablennamen, ein Kommentar, der sagt // bin mir unsicher, eine Funktion, die klar zweimal kopiert wurde. Der Code verrät seine eigene Fragilität. AI-Code tut das nicht. Er ist stilistisch konsistent, gut benannt und strukturiert auf eine Weise, die absichtlich wirkt. Das Selbstbewusstsein ist rein kosmetisch.// not sure about this, a function that's clearly copy-pasted twice. The code telegraphs its own fragility. AI code doesn't. It's stylistically consistent, well-named, and structured in a way that reads as intentional. The confidence is entirely cosmetic.

Studien der Stanford Human-Computer Interaction Group haben gezeigt, dass Entwickler, die AI-Assistants nutzen, dazu neigen, generierten Code beim ersten Lesen zu übervertrauen. Das entspricht meiner eigenen Erfahrung. Ich würde einen 40-Zeilen-Function von Copilot kurz anschauen, denken „ja, genau das hätte ich geschrieben", und weitermachen. Manchmal war es okay. Manchmal hatte er stillschweigend missverstanden, was ich eigentlich brauchte. have flagged that developers using AI assistants tend to over-trust generated code on first read. That tracks with my own experience. I would glance at a 40-line function Copilot had written, think "yeah, that's basically what I'd have written," and move on. Sometimes it was fine. Sometimes it had silently misunderstood what I actually needed.

Der spezifische Fehlermodus, auf den ich immer wieder stieß: bedingte Logik rund um Edge Cases, die die AI keinen Grund hatte, zu antizipieren. Sie würde eine Funktion schreiben, die den Happy Path perfekt handhabt und dann stillschweigend bei Null-Eingaben, leeren Arrays oder nicht-standardisierten Datumsformaten fehlschlägt. Dinge, die mich dreißig Sekunden gekostet hätten zu durchdenken, wenn ich den Code selbst geschrieben hätte, weil ich daran gedacht hätte, während ich tippte.conditional logic around edge cases the AI had no reason to anticipate. It would write a function that handled the happy path perfectly and then quietly fail on null inputs, empty arrays, or non-standard date formats. Things that would have taken me thirty seconds to think about if I'd written the code myself, because I'd have been thinking as I typed.

Die Geschwindigkeitsfalle

Hier lauert eine echte Produktivitätsfalle. Die KI macht dich schnell. Schnelligkeit fühlt sich gut an. Du fängst an, schneller zu liefern, und du überprüfst weniger sorgfältig, weil die Geschwindigkeit wie ein Zeichen für Qualität wirkt. Das ist sie nicht. Geschwindigkeit und Korrektheit sind nicht korreliert, wenn du ein Sprachmodell aufforderst.

Im September habe ich ungefähr 40% mehr Features in ein Kundenprojekt gesteckt, als ich ohne KI-Unterstützung geschafft hätte. Das Projekt hatte aber auch mehr Bugs nach dem Launch als alles, das ich in zwei Jahren ausgeliefert habe. Keine katastrophalen Bugs. Aber nervige. Die Art, die das Vertrauen des Kunden zermürbt.

---

Warum Tests jetzt anders funktionieren (Mit KI im Spiel)

Als ich zu Tests zurückkam, bin ich nicht zur alten Arbeitsweise zurückgekehrt. Tests schreiben, dann Implementierung, dann KI-gestützte Code-Review — das ist der Loop, bei dem ich gelandet bin.

Das Interessante ist, dass KI eigentlich ausgezeichnet darin ist, Tests zu schreiben, auf eine Weise, wie sie nicht immer ausgezeichnet darin ist, Anwendungslogik zu schreiben. Gib Copilot eine gut definierte Funktionssignatur und fordere es auf, eine Test-Suite zu generieren, und es produziert eine Edge-Case-Abdeckung, die ich 20 Minuten lang manuell geschrieben hätte. Es stellt sich unglückliche Pfade gut vor, wenn die Aufgabe speziell „finde Wege, wie das schiefgehen kann" ist.AI is actually excellent at writing tests, in a way it isn't always excellent at writing application logic. Give Copilot a well-defined function signature and ask it to generate a test suite and it'll produce edge-case coverage I'd have taken twenty minutes to write manually. It imagines unhappy paths well when the task is specifically "find ways this can break."

Ich habe das Ganze sozusagen invertiert. Ich schreibe die Test-Spezifikation. Die KI füllt die Test-Cases aus. Dann schreibt die KI die Implementierung. Dann lese ich die Implementierung durch die Linse dieser Tests, statt nur den Code kalt zu lesen.through the lens of those tests, rather than just reading the code cold.

Es ist langsamer als reines vibe-coding. Aber es ist schneller als der alte alles-manuell-schreiben-einschließlich-tests-Workflow. Und es hat seit Frankfurt null Permissions-Bugs ausgeliefert.

Die Tools, die ich tatsächlich nutze

  • [Vitest](https://vitest.dev) für alles mit JavaScript oder TypeScript. Hat Jest für mich im letzten Jahr vollständig ersetzt — die Konfiguration ist vernünftiger und der Watch-Modus ist schnell. for anything JavaScript or TypeScript. Replaced Jest for me entirely last year — the config is saner and the watch mode is quick.
  • PHPUnit weiterhin, für WordPress und benutzerdefinierte PHP-Arbeiten. Nichts hat es ersetzt. still, for WordPress and custom PHP work. Nothing has replaced it.
  • Cursors „test this function"-Shortcut — wirklich eines der nützlichsten einzelnen Features in jedem Editor, den ich je benutzt habe. — genuinely one of the most useful single features in any editor I've used.
  • GitHub Actions für CI. Tests laufen bei jedem Push zu main. Dauert bei den meisten Projekten etwa 90 Sekunden. for CI. Tests run on every push to main. Takes about 90 seconds on most projects.

---

Das Argument gegen Tests (Steel-Manned)

Ich möchte dieser Position eine faire Chance geben, weil ich sie fast zwei Jahre lang vertreten habe.

Das echte Argument ist nicht „Tests sind nutzlos." Es ist „Tests haben Kosten und viele Projekte rechtfertigen diese Kosten nicht." Eine Test-Suite zu schreiben und zu pflegen kostet Zeit. Bei einem Projekt mit kurzer Lebensdauer — eine Kampagnen-Mikrosite, eine Marketing-Landingpage, ein Hackathon-Prototyp — hat diese Zeitinvestition keinen Rückfluss. Das Projekt ist tot, bevor die Tests dir irgendetwas sparen.

Und es gibt einen subtileren Punkt: schlechte Tests sind schlimmer als keine Tests. Eine Test-Suite, die besteht, weil die Tests tautologisch sind (du testest im Grunde nur, dass deine Funktion das zurückgibt, was du ihr gesagt hast), gibt dir falsches Vertrauen. Ich habe das in Agenturen gesehen. Entwickler, die Tests schreiben, die immer bestehen, weil niemand hinterfragt hat, was sie wirklich überprüfen.bad tests are worse than no tests. A test suite that passes because the tests are tautological (you're essentially testing that your function returns what you told it to return) gives you false confidence. I've seen this at agencies. Developers writing tests that always pass because nobody challenged what they were actually verifying.

Martin Fowler hat sich dazu gut geäußert — Coverage-Prozentsätze sind kein Maß für Test-Qualität. Eine 90%-Coverage-Zahl kann eine völlig hohle Suite verschleiern. — coverage percentages are not a measure of test quality. A 90% coverage number can mask a completely hollow suite.

Also: nicht alles testen. Nicht testen, weil es sich professionell anfühlt. Testen, weil du eine Logik identifiziert hast, die tragend ist und teuer zu brechen wäre.

---

Was ich jetzt teste (und was nicht)

Hier ist die tatsächliche Entscheidung, zu der ich in den letzten acht oder neun Monaten gekommen bin:

Ich teste:

  1. Jede Funktion, die mit Geld, Berechtigungen oder Datentransformation umgeht
  2. Jeden API-Endpoint, der kein einfacher CRUD-Durchgang ist
  3. Custom Business Logic, bei der der Klient das exakte Verhalten schriftlich vorgegeben hat
  4. Alles, was eine KI geschrieben hat und das ich nicht Zeile für Zeile vollständig gelesen habe

Ich teste nicht:

  • UI-Rendering (Snapshot-Tests haben mir in neun Jahren nicht ein einziges Mal geholfen. Nicht ein einziges Mal.)
  • Wrapper für APIs von Drittanbietern, bei denen das externe Verhalten außerhalb meiner Kontrolle liegt
  • One-off-Scripts, die einmal laufen und dann gelöscht werden
  • Standard-WordPress-Hooks, es sei denn, sie machen etwas Ungewöhnliches

Das ist alles. Keine große Philosophie. Nur eine Liste basierend darauf, wo ich auf die Nase gefallen bin.

---

Der Workflow, der tatsächlich für mich funktioniert

Da ein paar Leute in Slack-Communities, in denen ich aktiv bin, danach gefragt haben, hier die tatsächliche Abfolge:

  1. Schreibe einen kurzen Spec-Kommentar oben in der Datei — was dieses Modul tut, was es nicht tut, Edge Cases, die ich bereits kenne.
  2. Bitte Cursor, Testfälle aus diesem Kommentar zu generieren, bevor ich irgendeine Implementierung schreibe.
  3. Überprüfe diese Testfälle. Lösche die dummen. Füge alle hinzu, die die KI übersehen hat.
  4. Lass Copilot oder Cursor die Implementierung schreiben.
  5. Führe die Tests aus. Sie werden fehlschlagen. Behebe die Implementierung (nicht die Tests).
  6. Lies das Diff vor dem Push — KI-gestützer Code braucht immer noch einen menschlichen Check.

Schritt 6 ist nicht verhandelbar. Ich habe in den letzten vier Monaten drei echte Bugs gefunden, nur indem ich das Diff langsam vor dem Push gelesen habe. Nichts Cleveres. Nur lesen.

Kent Becks ursprüngliche Rahmung von TDD war nie von 100% Coverage oder perfekter Methodik. Es ging darum, eine Feedback-Schleife schnell genug zu bauen, um Fehler zu fangen, bevor sie sich häufen. Diese Idee — schnelle Feedback-Schleifen — ist heute relevanter als 2003. Weil die KI Fehler schneller macht als jeder Developer, den ich je eingestellt habe. was never about 100% coverage or perfect methodology. It was about building a feedback loop fast enough to catch mistakes before they compound. That idea — fast feedback loops — is more relevant now than it was in 2003. Because the AI makes mistakes faster than any developer I've ever hired.

---

FAQ

Verlangsamt das deine Delivery-Geschwindigkeit?

Bei komplexen Projekten um etwa 10 bis 15%. Bei einfachen vielleicht gar nicht — die KI generiert die Tests so schnell, dass der Overhead minimal ist. Für Projekte, wo ein Bug nach dem Launch echtes Geld kostet (und die meisten echten Geld-Projekte fallen darunter), sind diese 15% hundertfach wert.

Und TypeScript? Ersetzt starke Typisierung nicht eine Menge Tests?

Teilweise. TypeScript fängt eine ganze Klasse von Fehlern zur Compile-Zeit ab, für die du früher Tests brauchtest. Aber Typen testen nicht die Geschäftslogik. Sie überprüfen nicht, ob deine Rabattberechnungsfunktion die richtigen Regeln für Großkundenkunden anwendet. Das liegt immer noch bei dir.

Sollten Junior-Entwickler KI-Coding-Tools verwenden, wenn sie keine Tests schreiben?

Nein. Das ist eine starke Meinung. Ein Junior-Entwickler, der Copilot ohne Tests nutzt, fliegt im Grunde ein Flugzeug auf Autopilot, ohne zu verstehen, wie der Autopilot funktioniert oder wie man manuell landet. Die KI produziert Code, der aussieht wie Senior-Level, der Junior wird nicht wissen, welche Teile er anzweifeln sollte, und du wirst irgendwann einen Produktionsvorfall haben. Tests geben ihm wenigstens einen Mechanismus, um die Ausgabe zu überprüfen, die er akzeptiert.

Warum hast du überhaupt damit angefangen, nicht mehr zu testen?

Burnout, teilweise. Und eine Zeit, in der jedes Projekt wirklich einfach war und Tests wirklich ihren Nutzen nicht rechtfertigten. Der Fehler war, nicht zu bemerken, wenn sich die Projektkomplexität änderte und sich entsprechend anzupassen. Das ist die echte Lektion — nicht „immer testen" oder „niemals testen", sondern zu wissen, in welche Kategorie ein bestimmtes Projekt fällt.

---

Tests zu schreiben fühlten sich nicht wie Schutz an. Sie fühlten sich wie Büroarbeit an. Die KI hat das geändert. Nicht, weil die KI schlecht ist — sie hat mich bedeutend schneller gemacht — sondern weil sie eine neue Klasse von selbstsicheren, gut formatierten, plausibel aussehenden Fehlern einführte, die ich nicht durch das Lesen von Code fangen kann, wie ich es früher tat. Die Tests sind nicht für die KI. Sie sind für mich. Eine Zwangsfunktion, um zu überlegen, was ich dem Code wirklich zum Tun brauche, bevor ich akzeptiere, was mir das Modell in die Hand gibt.

Ich wünschte, ich hätte es vor zwei Jahren so gerahmt.

< BACK