Im Februar veröffentlichten Meta-Forscher ein Papier mit dem Titel Automated Unit Test Improvement using Large Language Models at Meta, in dem sie ein Tool namens TestGen-LLM vorstellen. Der vollautomatische Ansatz zur Erhöhung der Testabdeckung „mit garantierten Garantien für Verbesserungen gegenüber der bestehenden Codebasis“ schlug in der Welt der Softwareentwicklung hohe Wellen.
Meta hat den TestGen-LLM-Code nicht veröffentlicht, also haben wir beschlossen, ihn als Teil unseres Open-Source Cover Agent 3.5K zu implementieren, und wir veröffentlichen ihn heute!
Ich werde hier einige Informationen darüber geben, wie wir bei der Implementierung vorgegangen sind, einige unserer Ergebnisse mitteilen und die Herausforderungen beschreiben, auf die wir bei der tatsächlichen Verwendung von TestGen-LLM mit realen Codebasen gestoßen sind.
Automatisierte Testerstellung: Grundlegende Kriterien
Automatisierte Testgenerierung mit generativer KI ist nichts Neues. Die meisten LLMs, die in der Lage sind, Code zu generieren, wie ChatGPT, Gemini und Code Llama, sind in der Lage, Tests zu generieren. Der häufigste Fallstrick, auf den Entwickler bei der Testgenerierung mit LLMs stoßen, ist, dass die meisten generierten Tests gar nicht funktionieren und viele keinen Mehrwert bieten (z. B. testen sie die gleiche Funktionalität, die bereits von anderen Tests abgedeckt wird).
Um diese Herausforderung (speziell für Regressionstests) zu meistern, haben die Autoren von TestGen-LLM die folgenden Kriterien aufgestellt:
1. Wird der Test korrekt kompiliert und ausgeführt?
2. Erhöht der Test die Codeabdeckung?
Ohne die Beantwortung dieser beiden grundlegenden Fragen hat es wohl keinen Sinn, den vom LLM generierten Test zu akzeptieren oder zu analysieren.
Sobald wir uns vergewissert haben, dass die Tests korrekt ausgeführt werden können und dass sie die Abdeckung unserer zu testenden Komponente erhöhen, können wir mit der Untersuchung beginnen (in einer manuellen Überprüfung):
- Wie gut ist der Test geschrieben?
- Wie viel Wert bringt er tatsächlich? (Wir alle wissen, dass die Codeabdeckung manchmal eine Ersatzgröße oder sogar eine Eitelkeitskennzahl sein kann)
- Erfüllt er zusätzliche Anforderungen, die wir möglicherweise haben?

Ansatz und berichtete Ergebnisse
TestGen-LLM (und Cover-Agent) laufen völlig kopflos (na ja, irgendwie schon; wir werden das später noch besprechen).
Zunächst generiert TestGen-LLM eine Reihe von Tests, filtert dann diejenigen heraus, die nicht gebaut/ausgeführt werden können, und verwirft schließlich diejenigen, die die Codeabdeckung nicht erhöhen. In stark kontrollierten Fällen beträgt das Verhältnis zwischen den generierten Tests und denen, die alle Schritte bestehen, 1:4, und in realen Szenarien berichten die Autoren von Meta von einem Verhältnis von 1:20.
Im Anschluss an den automatisierten Prozess ließ Meta die Tests von einem menschlichen Prüfer annehmen oder ablehnen. Die Autoren berichteten über ein durchschnittliches Annahmeverhältnis von 1:2, mit einer Annahmequote von 73 % in ihren besten Fällen.
Es ist wichtig anzumerken, dass das TestGen-LLM-Tool, wie in der Abhandlung beschrieben, bei jedem Durchlauf einen einzelnen Test erzeugt, der zu einer bestehenden Testsuite hinzugefügt wird, die zuvor von einem professionellen Entwickler geschrieben wurde. Außerdem generiert es nicht notwendigerweise Tests für eine bestimmte Testsuite.
Aus dem Papier: „Insgesamt wurden während der drei Test-a-thons 196 Testklassen erfolgreich verbessert, während das Tool TestGen-LLM auf insgesamt 1.979 Testklassen angewendet wurde. TestGen-LLM war also in der Lage, etwa 10 % der Testklassen, auf die es angewendet wurde, automatisch zu verbessern.“
Cover-Agent v0.1 ist wie folgt implementiert:
- Empfangen Sie die folgenden Benutzereingaben:
- Quelldatei für zu testenden Code
- Vorhandene Testsuite zum Erweitern
- Abdeckungsbericht
- Der Befehl zum Erstellen und Ausführen der Testsuite
- Codeabdeckungsziel und maximal durchzuführende Iterationen
- Zusätzliche Kontext- und Eingabeaufforderungsoptionen
2. Weitere Tests im gleichen Stil generieren
3. Validieren Sie diese Tests mit Ihrer Laufzeitumgebung
- Werden sie erstellt und bestanden?
4. Sicherstellen, dass die Tests einen zusätzlichen Nutzen bringen, indem Messwerte wie eine erhöhte Codeabdeckung überprüft werden
5. Aktualisierung der bestehenden Testsuite und des Abdeckungsberichts
6. Wiederholen Sie den Vorgang, bis der Code die Kriterien erfüllt: entweder die Schwelle für die Codeabdeckung ist erreicht, oder die maximale Anzahl an Iterationen wurde erreicht.
Herausforderungen, auf die wir bei der Implementierung und Überprüfung von TestGen-LLM gestoßen sind
Bei der Umsetzung des TestGen-LLM-Papiers in die Praxis stießen wir auf einige überraschende Herausforderungen.
In den Beispielen, die in dem Papier vorgestellt werden, wird die Verwendung von Kotlin für das Schreiben von Tests erwähnt – eine Sprache, die keine großen Leerzeichen verwendet. Bei Sprachen wie Python hingegen sind Tabulatoren und Leerzeichen nicht nur wichtig, sondern eine Voraussetzung für die Parsing-Engine. Weniger ausgereifte Modelle wie GPT 3.5 geben keinen Code zurück, der durchgängig richtig eingerückt ist, selbst wenn sie explizit dazu aufgefordert werden. Ein Beispiel, bei dem dies zu Problemen führt, ist eine in Python geschriebene Testklasse, bei der jede Testfunktion eingerückt sein muss. Wir mussten dies während des gesamten Entwicklungszyklus berücksichtigen, was die Komplexität der vorverarbeitenden Bibliotheken erhöhte. Es gibt noch viel zu verbessern, um Cover-Agent in Szenarien wie diesen robust zu machen.
Nachdem wir die speziellen Testanforderungen und Ausnahmen gesehen haben, auf die wir während unserer Versuche gestoßen sind, haben wir beschlossen, dem Benutzer die Möglichkeit zu geben, zusätzliche Eingaben oder Anweisungen zu geben, um den LLM als Teil des Cover-Agent-Flusses aufzufordern. Die Option -additional-instructions
ermöglicht es den Entwicklern, alle zusätzlichen Informationen, die für ihr Projekt spezifisch sind, bereitzustellen und Cover-Agent so anzupassen. Diese Anweisungen können beispielsweise verwendet werden, um Cover-Agent so zu steuern, dass es einen umfangreichen Satz von Tests mit sinnvollen Randfällen erstellt.
Im Einklang mit dem allgemeinen Trend der Retrieval-Augmented Generation (RAG), die sich in KI-basierten Anwendungen immer mehr durchsetzt, haben wir festgestellt, dass mehr Kontext bei der Generierung von Unit-Tests eine höhere Qualität der Tests und eine höhere Erfolgsquote ermöglicht. Wir haben die Option -included-files
für Benutzer bereitgestellt, die manuell zusätzliche Bibliotheken oder textbasierte Designdokumente als Kontext für den LLM hinzufügen möchten, um den Testgenerierungsprozess zu verbessern.
Komplexer Code, der mehrere Iterationen erforderte, stellte eine weitere Herausforderung für die LLMs dar. Als die fehlgeschlagenen (oder nicht wertschöpfenden) Tests generiert wurden, stellten wir ein Muster fest, bei dem dieselben nicht akzeptierten Tests in späteren Iterationen wiederholt vorgeschlagen wurden. Um dem entgegenzuwirken, fügten wir einen Abschnitt „Fehlgeschlagene Tests“ in die Eingabeaufforderung ein, um dem LLM dieses Feedback zu geben und sicherzustellen, dass er einzigartige Tests generierte und niemals Tests wiederholte, die wir für unbrauchbar hielten (d. h. fehlerhaft oder ohne Erhöhung der Abdeckung).
Eine weitere Herausforderung, die während dieses Prozesses auftrat, war die Unmöglichkeit, Bibliotheksimporte hinzuzufügen, wenn eine bestehende Testsuite erweitert wird. Entwickler können bei der Testerstellung manchmal kurzsichtig sein und nur einen einzigen Ansatz für das Testen von Frameworks verwenden. Neben den vielen verschiedenen Mocking-Frameworks können auch andere Bibliotheken bei der Testabdeckung helfen. Da das TestGen-LLM-Papier (und Cover-Agent) dazu gedacht ist, bestehende Testsuiten zu erweitern, ist die Möglichkeit, die gesamte Testklasse komplett umzustrukturieren, nicht vorgesehen. Dies ist meiner Meinung nach eine Einschränkung der Testerweiterung gegenüber der Testerzeugung und etwas, das wir in zukünftigen Iterationen angehen wollen.
Es ist wichtig zu unterscheiden, dass bei dem Ansatz von TestGen-LLM jeder Test eine manuelle Überprüfung durch den Entwickler erfordert, bevor der nächste Test vorgeschlagen wird. Beim Cover-Agent hingegen generieren, validieren und schlagen wir so viele Tests wie möglich vor, bis die Abdeckungsanforderung erreicht ist (oder wir bei der maximalen Anzahl an Iterationen aufhören), ohne dass während des gesamten Prozesses ein manuelles Eingreifen erforderlich ist. Wir nutzen KI, um im Hintergrund zu arbeiten, und schaffen so einen unaufdringlichen Ansatz zur automatischen Testgenerierung, der es dem Entwickler ermöglicht, die gesamte Testsuite zu überprüfen, sobald der Prozess abgeschlossen ist.

Schlussfolgerung und was als Nächstes kommt
Während viele, mich eingeschlossen, von dem TestGen-LLM-Papier und -Tool begeistert sind, haben wir in diesem Beitrag seine Grenzen aufgezeigt. Ich glaube, dass wir uns noch in der Ära der KI-Assistenten und nicht der KI-Kollegen befinden, die vollautomatische Arbeitsabläufe durchführen.
Gleichzeitig können ausgereifte Abläufe, die wir hier in Cover-Agent entwickeln und teilen wollen, uns Entwicklern helfen, automatisch Testkandidaten zu generieren und die Codeabdeckung in einem Bruchteil der Zeit zu erhöhen.
Wir haben die Absicht, die Entwicklung fortzusetzen und modernste Methoden im Bereich der Testerzeugung in das Open-Source-Repository von Cover-Agent zu integrieren.
Wir ermutigen jeden, der an generativer KI für das Testen interessiert ist, mitzuarbeiten und dabei zu helfen, die Fähigkeiten von Cover-Agent zu erweitern, und wir hoffen, Forscher zu inspirieren, dieses Open-Source-Tool zu nutzen, um neue Testgenerierungsverfahren zu erforschen.
Im Open-Source Cover-Agent Repo auf GitHub haben wir eine Entwicklungs-Roadmap hinzugefügt. Wir würden uns freuen, wenn Sie entsprechend der Roadmap oder nach Ihren eigenen Ideen zum Repo beitragen!
Unsere Vision für Cover-Agent ist, dass es in Zukunft automatisch für jede Pre/Post-Pull-Anfrage läuft und automatisch Regressionstest-Verbesserungen vorschlägt, die validiert wurden und die Codeabdeckung erhöhen. Wir stellen uns vor, dass Cover-Agent Ihre Codebasis automatisch scannt und PRs mit Testsuiten für Sie öffnet.
Lassen Sie uns KI nutzen, um die Aufgaben, die wir nicht gerne machen, effizienter zu erledigen!
P.S.
1. Wir sind immer noch auf der Suche nach einem guten Benchmark für derartige Tools. Kennen Sie einen? Wir denken, dass dies für die weitere Entwicklung und Forschung von entscheidender Bedeutung ist.
2. In unserer AlphaCodium-Arbeit finden Sie (a) weitere Informationen zum Thema „Flow Engineering“ sowie ein Beispiel für (b) einen wettbewerbsfähigen Programmier-Benchmark und (c) einen gut konzipierten Datensatz namens CodeContests.