Softwareentwicklung

KI-generierte Tests prüfen: Wie ich herausfinde, ob meine Tests wirklich Fehler finden

Automatisierte Tests gehören für mich inzwischen selbstverständlich zu KI-gestützter Softwareentwicklung, gleichzeitig verschiebt sich dadurch aber ein Problem, das leicht übersehen wird. Wenn Codex nicht nur den eigentlichen Code erzeugt, sondern anschließend auch einen großen Teil der Tests schreibt, kann ich zwar in kurzer Zeit eine beeindruckend große Testsuite erhalten, weiß damit aber noch nicht, ob diese Tests tatsächlich etwas Wertvolles prüfen. Zehn, fünfzig oder hundert grüne Tests sehen beruhigend aus, doch wenn sie dieselben Annahmen wiederholen, auf denen bereits die Implementierung basiert, können sie mir eine Sicherheit vermitteln, die in Wirklichkeit gar nicht vorhanden ist.

Meine automatisierten Tests sollen deshalb grundsätzlich nicht beweisen, dass die Software funktioniert, sondern möglichst Situationen finden, in denen sie das nicht tut. Daraus ergibt sich zwangsläufig die nächste Frage: Wer oder was überprüft eigentlich, ob die Tests selbst gut genug sind, um solche Fehler zu entdecken? Genau an dieser Stelle wird Testing für mich inzwischen zu einem eigenen Qualitätsproblem und nicht mehr nur zu einem nachgelagerten Schritt der Entwicklung.

Ein grüner Test kann auch dann grün sein, wenn er fast nichts beweist

Automatisierte Tests sind zunächst nur ausführbare Behauptungen darüber, wie sich Software in einer bestimmten Situation verhalten soll. Wenn diese Behauptung unvollständig, zu oberflächlich oder sogar fachlich falsch ist, kann der Test vollkommen zuverlässig genau das Falsche bestätigen.

Ein typisches Beispiel wäre eine Berechtigungsregel. Angenommen, eine Funktion darf nur unter bestimmten Voraussetzungen ausgeführt werden und Codex interpretiert diese Voraussetzungen bei der Implementierung falsch. Wenn anschließend aus demselben Verständnis ein Test entsteht, kann dieser genau das implementierte Verhalten prüfen und erfolgreich bestätigen, obwohl sowohl Code als auch Test von der eigentlichen fachlichen Anforderung abweichen.

Das ist für mich problematischer als ein offensichtlich fehlschlagender Test, weil die gesamte Kette plausibel aussieht. Der Code kompiliert, die Tests laufen und das Ergebnis vermittelt den Eindruck, die Anforderung sei abgesichert. Tatsächlich wurde lediglich ein gemeinsamer Denkfehler automatisiert.

Genau deshalb reicht mir langfristig auch eine zweite KI für das Testing allein noch nicht aus. Unabhängigkeit entsteht nicht automatisch dadurch, dass ein anderer Modellname auf der zweiten Seite steht.

Die Anzahl der Tests ist deshalb für mich ein schwaches Qualitätsmerkmal

Eine große Testsuite kann sinnvoll sein, aber ihre Größe sagt zunächst wenig darüber aus, welche Arten von Fehlern sie tatsächlich erkennen würde. Gerade KI macht es sehr einfach, viele ähnliche Fälle zu erzeugen, weil Variationen eines bestehenden Tests praktisch kostenlos entstehen können. Das kann die Abdeckung erhöhen und bei Grenzwerten durchaus hilfreich sein, erzeugt aber genauso leicht eine große Menge redundanter Prüfungen, die alle dieselbe fachliche Annahme bestätigen.

Mich interessiert deshalb zunehmend weniger, wie viele Tests eine Änderung besitzt, sondern welche Fehlerklassen dadurch tatsächlich abgesichert sind. Werden falsche Grenzwerte erkannt? Reagieren die Tests auf eine vertauschte Bedingung? Fällt auf, wenn eine Berechtigungsprüfung komplett entfernt wird? Würde ein Test bemerken, dass nach einem Neustart ein zuvor gespeicherter Zustand verloren geht, obwohl genau diese Persistenz fachlich gefordert war?

Diese Fragen sind deutlich schwieriger als die reine Messung von Testabdeckung, weil sie nicht nur fragen, welcher Code ausgeführt wird, sondern welche falschen Verhaltensweisen dadurch sichtbar würden.

Mutation Testing passt erstaunlich gut zu meiner Denkweise

Ein Verfahren, das mich deshalb besonders interessiert, ist Mutation Testing. Dabei wird der Programmcode absichtlich leicht verändert, sodass kontrolliert Fehler eingebaut werden. Anschließend wird geprüft, ob die vorhandenen Tests darauf reagieren.

Damit dreht sich die Fragestellung um. Statt nur zu fragen, ob die Tests unter normalen Bedingungen erfolgreich laufen, wird überprüft, ob sie absichtlich falschen Code überhaupt bemerken.

Wenn beispielsweise eine Bedingung von > auf >= verändert wird, ein Rückgabewert vertauscht, eine Prüfung entfernt oder ein boolescher Ausdruck umgedreht wird und sämtliche Tests trotzdem weiterhin grün bleiben, zeigt mir das ziemlich deutlich, dass die Tests an dieser Stelle weniger schützen, als es die reine Testanzahl vermuten lässt.

Genau deshalb gefällt mir Mutation Testing als Ergänzung zu KI-generierten Tests. Es bewertet nicht direkt, ob ein Test „gut geschrieben“ aussieht, sondern prüft seine praktische Wirkung gegen kontrolliert eingeführte Fehler.

Auch Mutation Testing ist kein automatischer Qualitätsbeweis

Natürlich darf daraus nicht die nächste vereinfachte Kennzahl werden, die anschließend blind optimiert wird. Ein hoher Mutation Score bedeutet nicht automatisch, dass alle fachlich relevanten Fehler abgedeckt sind. Wenn die erzeugten Mutationen nur technische Kleinigkeiten verändern, während die eigentlichen Produktannahmen unberührt bleiben, kann eine Testsuite sehr gut abschneiden und trotzdem eine falsche fachliche Interpretation vollständig übersehen.

Für mich ist Mutation Testing deshalb ein zusätzlicher Blickwinkel und kein Ersatz für gute Anforderungen, unabhängige Testideen oder echte Nutzungsszenarien.

Eine gute Spezifikation bleibt die Grundlage, weil Tests nur dann gegen das gewünschte Verhalten prüfen können, wenn dieses Verhalten außerhalb des Codes überhaupt ausreichend klar beschrieben wurde. Ohne diese unabhängige Referenz besteht immer die Gefahr, dass ich lediglich kontrolliere, ob Implementierung und Tests miteinander übereinstimmen, statt ob beide gemeinsam die richtige Sache tun.

Tests brauchen deshalb eine andere Informationsquelle als nur den Code

Je stärker ich meine Entwicklung automatisiere, desto wichtiger wird für mich die Trennung zwischen der Quelle einer Implementierung und der Quelle einer Prüfung. Wenn ein Test hauptsächlich aus dem vorhandenen Code abgeleitet wird, ist seine Fähigkeit begrenzt, genau diesen Code fachlich infrage zu stellen.

Deshalb möchte ich automatisierte Tests langfristig stärker aus Anforderungen und erwartbarem Verhalten erzeugen lassen. Ein Testsystem sollte beispielsweise wissen, dass eine bestimmte Aktion nur unter bestimmten Voraussetzungen erlaubt ist, ohne zunächst die dazugehörige if-Bedingung im Quellcode zu studieren und daraus wiederum die Erwartung abzuleiten.

Das heißt nicht, dass Tests keinerlei Zugriff auf die Implementierung haben dürfen. Für technische Prüfungen, Coverage oder gezieltes Mutation Testing ist dieser Zugriff selbstverständlich sinnvoll. Der fachliche Erwartungswert sollte aber möglichst aus einer anderen Quelle stammen.

Genau die Verbindung von Konzeptwissen und Codekontext wird damit zu einem zentralen Bestandteil meiner Qualitätssicherung.

Ein Test-Agent kann Tests erzeugen, aber auch dessen Arbeit muss begrenzt bleiben

In meinem heutigen Prozess kann ein spezialisierter Test-Agent zusätzliche Testfälle erzeugen und bewusst nach Situationen suchen, die bei der eigentlichen Umsetzung möglicherweise nicht berücksichtigt wurden. Das ist für mich bereits ein deutlicher Fortschritt gegenüber einer rein manuellen Situation, in der ich als allein arbeitender Entwickler dieselbe Funktion erst implementiere und anschließend aus demselben gedanklichen Kontext heraus teste.

Trotzdem bleibt der Agent ein Werkzeug und kein unabhängiger Mensch mit einer eigenen Vorgeschichte, anderen Erfahrungen und völlig anderen Annahmen. Gerade deshalb möchte ich die technische Trennung der Rollen nicht überschätzen.

Langfristig kann ich mir einen Prozess vorstellen, in dem unterschiedliche Systeme verschiedene Ebenen prüfen. Eine KI erzeugt die Umsetzung, ein anderes System leitet aus der Spezifikation Tests ab, Mutation Testing untersucht anschließend, ob die Tests absichtlich eingebaute Fehler erkennen, und weitere statische oder dynamische Prüfungen kontrollieren zusätzliche Eigenschaften der Software.

Der Vorteil eines solchen Ansatzes wäre nicht, dass irgendeine einzelne Instanz „die Wahrheit“ kennt, sondern dass mehrere unterschiedliche Fehlermechanismen weniger wahrscheinlich denselben blinden Fleck besitzen.

Der Aufwand wird durch KI plötzlich wirtschaftlich interessant

Früher hätte ich mir bei jeder normalen Funktion sehr genau überlegen müssen, wie viel zusätzliche Zeit ich in solche Meta-Prüfungen investiere. Wenn ich selbst den Code schreibe, anschließend die Tests entwickle und danach zusätzlich noch systematisch die Qualität dieser Tests prüfe, kann der Testaufwand schnell größer werden als die eigentliche Implementierung.

Mit KI verändert sich diese Rechnung.

Wenn Codex einen großen Teil der technischen Umsetzung übernimmt und zusätzliche Testfälle ebenfalls automatisch entstehen können, lässt sich ein Teil der gewonnenen Zeit wieder in strengere Qualitätssicherung investieren. Das ist für mich ein wichtiger Gedanke, weil KI nicht zwangsläufig nur dazu dienen muss, dieselbe Software schneller fertigzustellen. Sie kann genauso dazu genutzt werden, einen Qualitätsaufwand wirtschaftlich zu machen, den ich früher als Einzelentwickler kaum in diesem Umfang betrieben hätte.

Gerade als Einzelunternehmer verändert KI damit meine verfügbare Arbeitskapazität, ohne dass daraus automatisch weniger Qualitätskontrolle werden muss.

Tests dürfen auch bewusst gegensätzliche Perspektiven einnehmen

Neben technischen Mutationen interessieren mich deshalb auch bewusst adversariale Fragestellungen. Wenn eine Funktion einen klar definierten Normalablauf besitzt, kann ein Testsystem gezielt versuchen, diesen Ablauf in ungewöhnlichen Reihenfolgen, mit unerwarteten Eingaben oder unter unterbrochenen Bedingungen auszuführen.

Bei einem speichernden Vorgang wäre beispielsweise nicht nur interessant, ob gültige Daten korrekt gespeichert werden. Spannend ist genauso, was passiert, wenn die Verbindung während des Speicherns abbricht, derselbe Auftrag zweimal ankommt, der Prozess neu gestartet wird oder ein Teil der abhängigen Systeme nicht verfügbar ist.

Solche Tests entstehen aus einer anderen Denkweise als klassische Happy-Path-Prüfungen. Sie fragen nicht primär, ob die Funktion ihre Beschreibung erfüllt, sondern unter welchen Randbedingungen diese Beschreibung zusammenbricht.

Genau dort liegt für mich der größte Wert automatisierter Testgenerierung.

Testqualität muss in Agenda irgendwann ein eigener Zustand werden

Wenn meine Prozesskette über Agenda weiter automatisiert wird, reicht mir deshalb langfristig ein Zustand wie „Tests erfolgreich“ wahrscheinlich nicht mehr aus. Interessanter wäre eine differenziertere Aussage darüber, welche Prüfungen durchgeführt wurden und wie belastbar das Ergebnis tatsächlich ist.

Eine Aufgabe könnte beispielsweise normale Unit- und Integrationstests bestanden haben, während Mutation Testing gleichzeitig zeigt, dass bestimmte Bereiche kaum auf absichtlich eingebaute Fehler reagieren. Ein anderer Auftrag könnte fachliche Tests sauber bestehen, aber noch keine Prüfung auf Parallelität oder Neustartszenarien besitzen.

Das bedeutet nicht, dass Agenda irgendwann ein kompliziertes Qualitätspunktesystem benötigt. Mir geht es eher darum, „grün“ nicht als eindimensionalen Zustand zu behandeln.

Je automatisierter der Prozess wird, desto wichtiger wird die Information darüber, warum ich einem grünen Ergebnis vertrauen sollte.

Auch der beste automatische Testprozess wird menschliche Bewertung nicht vollständig ersetzen

Ich glaube nicht, dass sich Softwarequalität irgendwann vollständig auf einen perfekten Satz automatisierter Prüfungen reduzieren lässt. Gerade bei Benutzeroberflächen, ungewöhnlichen fachlichen Situationen oder neuen Produktideen gibt es weiterhin Dinge, die sich nur schwer vollständig formalisieren lassen.

Der Oma-Test ist ein gutes Beispiel dafür. Eine Anwendung kann sämtliche technischen Tests bestehen und trotzdem so aufgebaut sein, dass ein normaler Mensch ihre Bedienung nicht versteht. Kein Mutation Score wird mir dieses Problem automatisch erklären, wenn die Tests ausschließlich auf technische Korrektheit ausgerichtet sind.

Genau deshalb möchte ich unterschiedliche Qualitätsbegriffe nicht miteinander vermischen. Technische Tests, fachliche Erwartungen, Benutzerfreundlichkeit, Betrieb und Sicherheit beleuchten dasselbe Produkt aus verschiedenen Richtungen.

Automatisierung kann viele dieser Perspektiven verstärken, aber sie macht sie nicht identisch.

Für mich ist der wichtigste Fortschritt deshalb nicht „mehr Tests“

Ich möchte langfristig nicht stolz darauf sein, dass ein Projekt zehntausend automatisch erzeugte Tests besitzt. Interessanter wäre für mich die Aussage, dass meine Tests nachweislich auf unterschiedliche Arten von Fehlern reagieren, dass ihre Erwartungen unabhängig genug von der Implementierung entstehen und dass ich weiß, welche Bereiche noch schwach abgesichert sind.

Dafür muss ich die Tests selbst genauso kritisch behandeln wie den Code, den sie prüfen sollen.

Eine KI-generierte Testsuite ist deshalb für mich kein Endprodukt der Qualitätssicherung, sondern zunächst eine weitere technische Arbeit, deren Qualität bewertet werden muss. Genau darin liegt wahrscheinlich der nächste Schritt meiner Automatisierung: Nicht nur Software automatisch zu erzeugen und zu testen, sondern auch zunehmend automatisch herauszufinden, wie viel Vertrauen die Tests selbst eigentlich verdienen.

Wenn das irgendwann zuverlässig gelingt, wird ein grüner Testlauf für mich deutlich mehr bedeuten als heute. Nicht weil grüne Tests plötzlich beweisen, dass keine Fehler existieren, sondern weil ich wesentlich besser einschätzen kann, welche Art von falschem Verhalten sie tatsächlich entdeckt hätten.