Metas neuer LLM-basierter Testgenerator
(read.engineerscodex.com)Metas neuer LLM-basierter Testgenerator bietet einen Ausblick auf die Zukunft der Entwicklung
- Meta hat ein Paper mit dem Titel "Automated Unit Test Improvement using Large Language Models at Meta" veröffentlicht.
- Das Paper zeigt, wie sich mit KI die Entwicklung beschleunigen und die Zahl von Softwarefehlern reduzieren lässt.
- Durch die Integration von LLMs in den Workflow von Entwicklerinnen und Entwicklern werden präzise und vollständige Verbesserungsvorschläge für Software gemacht, die die aktuelle Code Coverage erhöhen.
Wichtige Punkte
- TestGen-LLM verwendet den Ansatz „Assured LLM-based Software Engineering“ (Assured LLMSE).
- Es nutzt einen Ensemble-Ansatz, bei dem mehrere LLMs, Prompts und Hyperparameter verwendet werden, um Code-Verbesserungen zu erzeugen und anschließend die beste Verbesserung auszuwählen.
- TestGen-LLM wurde speziell dafür entwickelt, bestehende von Menschen geschriebene Tests zu verbessern.
Statistiken
- Bei der Auswertung der Produkte Reels und Stories auf Instagram wurden 75 % der von TestGen-LLM erzeugten Testfälle erfolgreich gebaut, 57 % bestanden zuverlässig, und 25 % erhöhten die Coverage.
- TestGen-LLM konnte 10 % aller angewendeten Klassen verbessern, und Entwicklerinnen und Entwickler übernahmen 73 % der Testverbesserungen und setzten sie in Production ein.
- Bei einem „test-a-thon“, bei dem Meta-Ingenieurinnen und -Ingenieure Tests erzeugten, um die Test Coverage von Instagram zu erhöhen, lag der Median der von TestGen-LLM-Tests hinzugefügten Codezeilen bei 2,5.
Praktisch nutzbare Erkenntnisse
- Dies ist ein gutes Beispiel dafür, wie sich mit LLMs die Produktivität in der Entwicklung und die Zuverlässigkeit von Software effizient steigern lassen.
- Der eigentliche Wert von LLMs liegt darin, unerwartete Edge Cases zu finden und abzufangen.
- Um LLMs in Production einzusetzen, sind Orchestrierung, Pipelines und Verarbeitung erforderlich.
Wie TestGen-LLM funktioniert
- TestGen-LLM wendet auf von Metas internem LLM erzeugte Kandidatenlösungen eine Reihe semantischer Filter an, um nur die wertvollsten Tests zu behalten.
- Filter 1: Build-Fähigkeit, Filter 2: Ausführung (ob Tests bestehen), Filter 3: Flakiness, Filter 4: Verbesserung der Coverage.
- Diese Verarbeitungsfilter stellen eine Verbesserung der Test-Suite sicher.
Fazit
- Dieses Paper ist eine gute Möglichkeit, die Fortschritte von LLMs im Bereich Software-Zuverlässigkeit nachzuverfolgen, da viele Entwicklerinnen und Entwickler LLMs bereits nutzen.
- LLMs werden zunehmend in der Lage sein, Bugs in immer komplexeren Softwaresystemen zu finden und zu testen.
Meinung von GN⁺
- Dieser Artikel bietet interessante Einblicke darin, welchen Einfluss Künstliche Intelligenz auf die Zukunft der Softwareentwicklung haben kann.
- Tools wie TestGen-LLM können eine große Hilfe dabei sein, die Arbeit von Entwicklerinnen und Entwicklern zu automatisieren und die Effizienz zu steigern.
- Die Weiterentwicklung solcher Technologien geht in Richtung geringerer Komplexität in der Softwareentwicklung, höherer Qualität und Zeitersparnis für Entwicklerinnen und Entwickler.
1 Kommentare
Meinungen auf Hacker News
Interessant ist der Trend, LLMs zuerst für das Schreiben von Testcode einzusetzen, statt für die Implementierung.
Vielleicht habe ich zu viel TDD gemacht, aber für mich beschreiben Tests, wie sich ein System verhalten soll, und das sollte von Menschen definiert werden. Der Code sollte sich innerhalb der Leitplanken bewegen, die die Tests vorgeben.
Allerdings können LLMs dabei helfen, Bereiche aufzuzeigen, in denen die Spezifikation unzureichend ist. Vielleicht passiert hier genau das: Man lässt sie Unit-Tests für weniger gut spezifizierte Bereiche vorschlagen.
Schon vor LLMs habe ich gelegentlich darüber nachgedacht, ob nicht ein Affe mit einer Schreibmaschine eine Anwendung bauen könnte, wenn nur alle Tests vorher geschrieben wären.
Das sind Tests, die nicht definieren, wie Menschen glauben, dass sich der Code verhalten sollte, sondern wie sich die aktuelle Codebasis tatsächlich verhält.
Dadurch kann man neu schreiben, refaktorisieren und neu entwerfen, während Regressionen minimiert werden. Das Problem vieler Legacy-Codebasen ist, dass niemand das beabsichtigte Verhalten versteht; manchmal glauben sogar Nutzer, dass sich das System anders verhalten sollte, als es tatsächlich tut.
Deshalb ist es am wichtigsten, das Verhalten nicht zu ändern, sofern es sich nicht um eine ausdrücklich gewünschte Änderung handelt.
Die Grundidee ist, Aussagen über das Codeverhalten, die schwächer sind als ein vollständiges geschlossenes Beweissystem, als „Properties“ auszudrücken und sie innerhalb im Kern probabilistischer Grenzen zu überprüfen.
Das klassische Beispiel ist das Umkehren von Strings: Wenn man einen String zweimal umkehrt, sollte normalerweise wieder die Eingabe herauskommen. Mit einer Zeile Code kann man so viele seltsame Unicode-Grenzfälle prüfen, wie Zeit und Strom erlauben.
Das Beispiel wirkt trivial, aber ich habe gesehen, wie CUDA-Experten, die an automatischer Differenzierung und Kernel-Arbeit für das spätere PyTorch arbeiteten, diesen Ansatz extrem gut nutzten und mit etwa halb so viel Aufwand und Kosten ungefähr die fünffache Code-Zuverlässigkeit erzielten.
Es passt nicht immer, aber wenn es passt, ist es hervorragend; und LLMs scheinen schon zu Beginn ziemlich nahe an Hypothesis-Beispiele heranzukommen.
Beim Schreiben von Tests hingegen muss man in einer extrem wortreichen und stark eingeschränkten Sprache beschreiben, was die Anwendung tun soll, und für ein paar verherrlichte if/else-Blöcke Dutzende oder Hunderte Zeilen Setup-Code schreiben.
In Sprachen wie C++ oder Java bestehen Unit-Tests aus Langeweile; daher überrascht es überhaupt nicht, dass der Instinkt entsteht, diese Arbeit einem LLM zu überlassen.
Ich habe viele Engineers gesehen, die tagelang Code schreiben und danach notgedrungen ein paar Tests verfassen, um zu „beweisen“, dass das System funktioniert. Die Coverage ist niedrig und meist fragil.
Für Engineers, die so denken und arbeiten, wirkt ein solches System wie ein Geschenk des Himmels.
Ich hatte auch einmal einen Manager, der untersagte, Tests zuerst zu schreiben, weil das zu langsam sei. Zum Glück war ich als Externer dort und konnte ihn mit „Sprechen Sie mit meinem Chef“ ignorieren, aber vermutlich dachte er genauso wie die oben genannten Engineers.
Anders betrachtet: Die meisten Entwickler hassen Dokumentation. Wenn es eine KI gäbe, die aus Code hervorragende Dokumentation schreibt, würden sie sie mögen. Und für solche Entwickler ist Dokumentation, die sie nicht selbst schreiben müssen, hervorragende Dokumentation.
Testcode wird oft als Code mit niedriger Priorität behandelt und eher Junior Engineers überlassen, was genau in die falsche Richtung zu gehen scheint.
Ich möchte nicht alles im Detail prüfen, aber ein Punkt scheint besonders weit daneben zu liegen.
Unter dem Vorbehalt, dass ich das ursprüngliche Paper kurz nach Erscheinen nur grob gelesen habe und es jetzt gerade überfliege, meine Erinnerung also etwas verschwommen ist:
Der Blog schrieb, dass die meisten Tests von Metas TestGen-LLM nur zusätzliche 2,5 Zeilen abdeckten, ein Test aber 1326 Zeilen abdeckte, und dass der Wert dieses einen Tests „exponentiell größer“ sei; außerdem sei es besonders wertvoll, dass das LLM aktiv über den Tellerrand hinaus denke und unerwartete Grenzfälle finde.
Schon die Formulierung „exponentiell wertvoller“ sollte allerdings den Bullshit-Detektor auslösen. Im Paper beschreiben die Autoren diese 1326 Zeilen Coverage als einen einzelnen Jackpot-Test und sagen, dass die realistisch zu erwartende zusätzliche Zeilenabdeckung eines einzelnen TestGen-LLM-Tests im Median 2,5 Zeilen beträgt.
Die Autoren erwähnen weder „unerwartete Grenzfälle“ noch „über den Tellerrand hinausdenken“. Vielmehr stellen sie es als Ausnahmefall dar, bei dem möglicherweise ein Zweig eines schrecklichen switch-Statements getroffen wurde oder es sich um einen Zufall der Code-Coverage-Berechnung handelte.
Auffällig ist auch, dass sie dem im Abschnitt „Qualitative Ergebnisse“ nicht weiter nachgehen. Ungenaue Erläuterungen helfen niemandem. Im Internet gibt es bereits zu viele Menschen, die so tun, als hätten sie verstanden, was sie nur vorgeben gelesen zu haben.
Ich habe den Text geändert, damit klarer wird, dass einige Interpretationen meine eigene Meinung sind.
Der Beitrag ist eher ein Kommentar dazu, was die Ergebnisse des Papers bedeuten, als eine Zusammenfassung des Papers. Schließlich ist Hacker News ein Ort für Diskussionen.
Trotzdem halte ich den Teil mit „exponentiell wertvoller“ weiterhin für richtig. Dass ein LLM in Bezug auf Test-Coverage zufällig einen „Jackpot“ treffen kann, ist genau der Kern des Werts.
Wenn man immer weiter verschiedene Kombinationen ausprobiert und wie im Paper nur einen einzigen Jackpot trifft, ist das für ein Team sehr wertvoll. Es kann ein Test sein, der für Menschen nicht offensichtlich oder einfach zu langweilig gewesen wäre, um ihn selbst zu schreiben.
Aus meiner Perspektive, in der ich in Big-Tech-Codebasen (F/G) oft schon wusste, was getestet werden sollte, aber zu viel Zeit darauf verwendete, herauszufinden, „wie man es testet“, ist dieser Wert groß.
Dieses Team wird offensichtlich ebenfalls in Richtung Zeilenzahl und Anzahl der Diffs gedrängt. Am Ende wird es nur ein weiteres Codegenerierungs-Tool, das einen weiteren schwer zu debuggenden Codeberg erzeugt.
Gute Tests sind schwierig, und Coverage ist nicht automatisch gut
Es ist leicht, so viele Tests zu schreiben, dass man das Programm verfestigt und praktisch ein Änderungs-Erkennungsprogramm baut. Dann läuft es auf etwas hinaus wie: „Sie haben etwas geändert, alle Tests sind kaputt. Kein Problem, jetzt lassen wir sie einfach vom LLM neu generieren! 100 % Coverage! Erstaunlich! Fortschritt!“
Für mich ist das eine Gelegenheit zu prüfen, ob diese Änderung beabsichtigt war. Wie soll man ohne das wissen, ob das Programm tut, was es tun soll?
Abgesehen davon muss man gute Tests lesen, die fünf andere Leute für gut hielten. Wir alle schreiben Tests schlecht, jeder nur auf seine eigene Weise
Danach drückte der Entwickler bei jeder Änderung ganz selbstverständlich auf den Regenerieren-Button und committete alles. Der Diff war reichhaltig, aber das Signal fragwürdig
Nachdem ich in der Halbleiterbranche gearbeitet habe, insbesondere in der Computational Lithography, wo testgetriebenes Design Standard ist, kann ich dem nur schwer zustimmen
Das heißt nicht, dass Tests immer vor dem Produktionscode geschrieben werden müssen. Aber Tests sind genauso Teil des Codes wie jeder andere Teil der Codebasis und müssen zwingend zusammen mit dem zu testenden Code geschrieben werden
Der wichtigste Teil von Tests ist, dass sie die Absicht des Entwicklers zeigen. Eine Testsuite zeigt, wie Code verwendet werden soll, was er tut, was er nicht tut und wofür er geschrieben wurde
Dann muss ein anderer Entwickler, der diesen Code verwendet oder ändert, nicht wie Sherlock Holmes in der Codebasis nach Hinweisen suchen
Wenn Tests keine Geschichte erzählen, schreibt man Tests falsch
Bis Computer Gedanken lesen und Absichten besser verstehen können, kann ein KI-/LLM-basierter Generator diese Aufgabe nicht übernehmen
Wenn das einzige Ziel einer Testsuite natürlich darin besteht, beim Pre-Commit-Check ein grünes Häkchen zu bekommen und schöne Coverage-Zahlen zu zeigen, kann KI die Produktivität verdoppeln
Automatische Codegeneratoren werden dabei helfen, schlechten Code mit Lichtgeschwindigkeit in noch größeren Mengen zu schreiben. Wenn jemand sich beschwert, dass der Code wegen viel Boilerplate aufgebläht und schwer verständlich ist, sagt man eben, er solle es mit KI erledigen. Bei Ihnen hat es ja funktioniert
So sieht die Zukunft der Entwicklung wirklich aus, aber es ist nicht die Zukunft, auf die ich hoffe
Was beschrieben wurde, scheint eher Tests am „Kern“ des Codes zu betreffen. Tests, die zugleich einen Teil von Dokumentation, Verifikation und Stabilität übernehmen
Andere Tests wie Fuzzing liefern einen völlig anderen Wert. KI-basierte Tests könnten einen Raum besetzen, der auf den Rand der Verteilung zielt: viele Tests mit geringerem Einzelwert, die liegen bleiben, weil Menschen nicht genug Energie und Zeit haben
So sehe ich auch den aktuellen Zustand von KI-Tools. Sie sind kognitive Hilfswerkzeuge
Ich wäre eher überrascht, wenn diese Forschungsrichtung in den nächsten Jahren nicht ziemlich Früchte trägt
Ich zitiere noch einmal leicht überarbeitet, was ich geschrieben habe, als das Paper selbst gepostet wurde. Deren Text stellt die Statistik falsch dar
https://news.ycombinator.com/item?id=39406726
Das Abstract passt nicht zum tatsächlichen Inhalt des Papers. Die Zusammenfassung liest sich so, als seien es Anteile auf Ebene der Testfälle: „75 % bauen korrekt, 57 % bestehen stabil, 25 % erhöhen die Coverage“
Der eigentliche Bericht spricht jedoch von Testklassen, und jede Klasse enthält einen oder mehrere Testfälle
Gemeint ist: „75 % der Testklassen hatten mindestens einen neuen Testfall, der korrekt baut“, „57 % der Testklassen hatten mindestens einen Testfall, der korrekt baut und stabil besteht“, „25 % der Testklassen hatten mindestens einen Testfall, der im Vergleich zu anderen Testklassen desselben Build-Targets baut, besteht und die Line Coverage erhöht“
Das sind völlig andere Aussagen. Es gibt sogar eine Fußnote, dass bei jedem Versuch, eine Testklasse zu erweitern, mehrere Versuche zur Generierung von Testfällen möglich sind, sodass die Erfolgsquote pro Testfall in der Regel deutlich niedriger ist als die Erfolgsquote pro Testklasse
In der Schlussfolgerung stellen sie die Ergebnisse dann aber wieder falsch dar, wie im Abstract. Sie schreiben, dass beim Einsatz von TestGen-LLM im Experimentiermodus die Erfolgsquote pro Testfall 25 % betrug und dass sie auf 57 % steigt, wenn man die Anforderung an die Line Coverage lockert und nur Build und Bestehen verlangt
Ich habe Mitgefühl mit den Leuten, die künftig diesen schrecklichen LLM-Legacy-Code warten müssen
Es wird hässlich werden
Vielleicht sieht es sogar ziemlich ähnlich aus, nur mit besseren Kommentaren und besserer Dokumentation und möglicherweise mit geringerer Wahrscheinlichkeit, aktiv falsch zu sein
LLMs werden niemals besser werden als jetzt und haben sich in den letzten zwei Jahren überhaupt nicht weiterentwickelt. Sie sind nur schicke Markov-Ketten
Zum Schreiben von Code kann man sie nur verwenden, wenn jemand, der nicht programmieren kann, blind und ohne Review Code in die Produktion committet
Für jemanden, der programmieren kann, können sie unmöglich nützlich sein und die Produktivität auch nicht steigern
Ich werde diesen LLM-Unsinn ignorieren, der die Welt überhaupt nicht verändert, und Sie sollten das unbedingt auch tun
Wenn man das nicht sauber trennt, wird daraus schnell eine entwicklerfeindliche Umgebung: Ein ahnungsloser Manager fordert hohe Coverage, und enthusiastische Juniors schleusen massenhaft AI-Tests ein.
Am Ende muss man bei jeder Einreichung den Stempel von schwer wartbarem, per LLM generiertem Testcode bekommen.
Manche Tests lassen sich dadurch vielleicht schneller schreiben, aber es gibt keine Garantie, dass die Wartung schneller wird. Dasselbe gilt für die Wartung des zu testenden Codes. Denn es gibt keine Garantie, dass gute Tests generiert werden.
Der mühsame Prozess des Testschreibens hilft Entwicklern normalerweise auch dabei, das Design früh zu überprüfen. Wenn etwas schwer zu testen ist, ist es meist kein gutes Design; etwa in Kontexten, in denen man gemeinsam mit anderen Code schreiben muss, sind Komponentenverträge oft nicht ausreichend abstrahiert.
Was leicht übersehen wird: Tests sind verzichtbarer Code. Die meisten werden ihr ganzes Leben lang nie etwas finden, und das ist in Ordnung. Denn sie geben automatisierte Sicherheit und grenzen bei Fehlern die falschen Spuren ein.
Aber maximale Investition in probabilistische Sicherheitsnetze zahlt sich nicht immer aus. Je näher die Coverage an die Spitze kommt, desto geringer wird der Grenznutzen. Wenn es sich nicht um stark frequentierte Ausführungspfade wie in einer Standardbibliothek handelt, wird hohe Coverage als Prestige meist nicht belohnt.
Außerdem braucht es fast immer nicht nur Unit-Tests, sondern ein Test-Ökosystem aus Integrations-, Systemtests und Ähnlichem, damit das Ganze funktioniert. Wird ein LLM in Design-Meetings sitzen, die Architektur verstehen und auch solche Tests schreiben? Oder werden seine Fähigkeiten übertrieben dargestellt und verdrängen das, was eigentlich getan werden müsste?
Wenn man Aufwand in Tests investiert, braucht man nicht nur beim Schreiben, sondern auch bei Design und Wartung ein Gespür dafür, „was relevant ist“. Menschen sind darin ziemlich gut, AI-Tools nicht.
Wobei LLMs Zeit sparen können, sind die Tastatureingaben erfahrener Entwickler, die bereits ein Gefühl dafür haben, was getestet werden sollte und was nicht. Gleichzeitig können sie auch stören, indem sie eher irrelevante Dinge heimlich in den Code bringen – und das haben sie bereits getan.
Ich will keine Ökonomie, die Tastatureingaben produziert. Ich will eine Menge gut durchdachter, hochrelevanter Tastatureingaben. Und ich hoffe, dass Letztere sauber von Ersteren getrennt werden, sodass sich mit der Zeit ihr objektiver Nutzen – oder dessen Fehlen – zeigt.
Habe ich bereits mit GPT-4 ausprobiert.
Ich habe ihm ein TypeScript-Modul gezeigt und es Unit-Tests generieren lassen; es hat funktionierende Tests erzeugt, die nicht nur den Happy Path, sondern auch einige Randfälle abgedeckt haben.
ChatGPT übertrifft in vielerlei Hinsicht die Erwartungen. Tests wirken gemessen an GPTs Fähigkeiten eher einfach.
Letzte Woche habe ich es Python-Code schreiben lassen, der einen AST durchläuft und daraus einen React-Flow-Graphen samt Komponenten erstellt. Ich habe nichts manuell korrigiert, sondern nur ein paar Runden Prompt-Feedback gegeben, und es funktionierte sehr gut. Ich habe bei GPT viele ähnlich interessante Fähigkeiten gesehen.
Woher weiß AI, welche Tests geschrieben werden sollten?
Ein interessantes Experiment, aber ich bin etwas skeptisch. Meiner Ansicht nach kann AI in der Softwareentwicklung am besten helfen, wenn Programmierer Fragen zu ihrem eigenen Code oder zum Code anderer stellen und die AI antwortet. Manchmal kann das Codevorschläge enthalten, muss es aber nicht immer.
Sie sollte Fragen beantworten können wie: „Gibt es eine Möglichkeit, diesen Code zu vereinfachen?“ oder „Welche Eingaben könnten Fehler auslösen?“
AI sollte uns helfen, Code zu verstehen und zu verstehen, wie wir ihn verbessern können. Wenn wir ihr nicht sagen, was sie tun soll, kann AI nicht wissen, was wir wollen; deshalb sollten wir sie nicht alles selbst schreiben lassen.
Tests sind ein gutes Beispiel. Was wollen wir testen?
Endlich eine überzeugende Form von AI-Codegenerierung