tsma – Die Verteidigungslinie gegen Regressionen in Legacy-Code Image: AI generated

Wenn Sie Legacy-Code mit KI refaktorieren wollen, aber es keine Tests gibt, wenn Ihr LLM Tests schreibt, aber auf halbem Weg aufhoert, wenn Sie die Abdeckung mechanisch verfolgen und dabei den Agenten steuern wollen – tsma baut diese Verteidigungslinie.

Wie refaktoriert man Code ohne Tests?

Man erbt 100.000 Zeilen Legacy-Code. Keine Tests. Man will refaktorieren, aber weiss nicht, was kaputtgeht, wenn man etwas anfasst. Um Tests zu schreiben, muss man den Code verstehen, und um den Code zu verstehen, braucht man Dokumentation – die es nicht gibt.

Niemand fasst es an. Es verrottet weiter.

Jeder Legacy-Code weltweit steckt in dieser Sackgasse. 60-80 % des IT-Budgets von Fortune-500-Unternehmen fliessen in die Wartung von Legacy-Systemen. 42 % der Entwicklerzeit werden fuer technische Schulden aufgewendet.

Was, wenn ein LLM die Tests stattdessen schreiben koennte?


Die Probleme, wenn man Tests dem LLM ueberlaesst

Wenn man einem LLM sagt: “Schreib einen Test fuer diese Funktion”, kommt irgendetwas heraus. Es gibt drei Probleme.

Erstens: Man weiss nicht, wo man anfangen soll. Bei 527 Funktionen – der Reihe nach ab Nummer 1? Die wichtigsten zuerst? Es gibt kein Kriterium.

Zweitens: Die Qualitaet der Tests laesst sich nicht ueberpruefen. Der vom LLM geschriebene Test ist bestanden. Aber prueft dieser Test tatsaechlich das Verhalten der Funktion, oder ist es nur eine leere Huelle, die die Funktion aufruft, ohne ein einziges assert? Man muss jeden Test einzeln lesen, um das herauszufinden.

Drittens: Ohne Feedback bleibt das LLM bei 60-70 % stehen. Gemaess der empirischen Studie von Schafer et al. (2023) liegt der Median der von LLM generierten Tests bei 70.2% Statement Coverage und 52.8% Branch Coverage. Allein mit “Teste diese Funktion” erreicht man keine 100 % Branch-Coverage. Man muss dem LLM mitteilen, welche Zweige fehlen, damit es den Rest abdeckt.

Das LLM kann nicht keine Tests schreiben. Das Problem ist, dass es keine Struktur gibt, die dem LLM sagt, was es testen soll und wie gut es getestet hat.


tsma: Eine Test-Schiene, die mit einem Befehl laeuft

tsma ist ein CLI-Tool, das alle Funktionen eines Projekts indexiert, den Teststatus erkennt, Coverage misst und dem LLM-Agenten praezises Feedback gibt.

Der Agent muss nur einen Befehl kennen:

$ tsma next

Dieser eine Befehl treibt die gesamte Schleife an:

$ tsma next          # Zeigt die naechste Funktion ohne Test
  → Test schreiben
$ tsma next          # Erkennt den neuen Test, fuehrt ihn aus, misst Coverage
  → 100%? PASS, weiter zur naechsten Funktion
  → <100%? Zeigt nicht abgedeckte Zweige mit Zeilennummern
$ tsma next          # Misst den korrigierten Test erneut
  → Verbessert oder nicht, markiert als DONE und weiter

Wiederholen, bis “All functions complete!” erscheint.


Validiert an 527 Funktionen

tsma wurde an einem realen Go-Projekt mit 527 Funktionen eingesetzt.

ErgebnisAnzahlAnteil
PASS (100 % Branch-Coverage)24646.7 %
DONE (Best-Effort)28153.3 %
TODO (nicht bearbeitet)00 %

246 Funktionen erreichten 100 % Branch-Coverage. Die uebrigen 281 erreichten keine 100 %, aber Tests wurden so weit wie moeglich geschrieben.

Warum erreichen manche Funktionen keine 100 %?


Funktionen, die 100 % erreichen – und solche, die es nicht tun

Ob eine Funktion 100 % Branch-Coverage erreichen kann, haengt davon ab, wie sie ihre Abhaengigkeiten bezieht.

Interface (mockable) – 100 % erreichbar:

type Handler struct {
    svc AuthSvc              // interface -- durch Mock ersetzbar
}

Im Test injiziert man ein Mock und kann alle Pfade steuern:

svc := mocks.NewMockAuthSvc(ctrl)
svc.EXPECT().Login(...).Return(result, nil)   // Erfolgspfad
svc.EXPECT().Login(...).Return(nil, err)      // Fehlerpfad

Konkreter Typ (not mockable) – 100 % nicht erreichbar:

type Handler struct {
    svc *service.SMSImportService    // Struct-Pointer -- nicht ersetzbar
}

Die tatsaechliche Implementierung laeuft mit internen Abhaengigkeiten wie Datenbanken oder externen APIs. Man kann keinen bestimmten Fehler ausloesen oder ein bestimmtes Ergebnis erzwingen. Zweige, die von solchen Ergebnissen abhaengen, sind per Unit-Test nicht erreichbar.

tsma reagiert darauf: Nach dem Feedback zu nicht abgedeckten Zweigen wird ein weiterer Versuch unternommen. Wenn die Zweige trotzdem nicht erreicht werden, wird die Funktion als DONE akzeptiert. Das ist keine Einschraenkung des Tools, sondern spiegelt die Testbarkeit des Codes wider. Das von Feathers (2004) systematisierte Legacy-Code-Dilemma – “um den Code zu aendern, braucht man Tests; um Tests hinzuzufuegen, muss man den Code aendern” – wird durch das Aufbrechen von Abhaengigkeiten und die Einfuehrung von Interfaces (DI) geloest. Mit Interfaces waeren 100 % moeglich – aber das bedeutet, den Originalcode zu aendern.


Feedback veraendert die Tests des LLM dramatisch

Der eigentliche Wert von tsma liegt weder im Indexieren noch in der Coverage-Messung. Er liegt darin, nicht abgedeckte Zweige mit exakten Zeilennummern anzuzeigen.

Ohne Feedback:

"Schreib einen Test fuer die Funktion ListContracts"
→ LLM testet nur den Happy Path
→ Coverage 60-70 %

Mit Feedback:

"Schreib einen Test fuer die Funktion ListContracts"
→ Coverage 65 % (11/17)
→ UNCOVERED:
    line 41 -- if params.Status != nil
    line 44 -- if params.BuildingId != nil
    line 70 -- if err != nil (CountSummary)
→ LLM fuegt Tests hinzu, die genau diese Zweige abdecken
→ Coverage 100 %

Dasselbe LLM. Der einzige Unterschied ist das Feedback. Drei Zeilen mit Zeilennummern trennen 60 % von 100 %. CoverUp (Pizzorno & Berger, 2024) hat dasselbe Prinzip empirisch belegt. Durch wiederholtes Einfuegen der Coverage-Analyseergebnisse in Prompts und Fokussierung der LLM-Aufmerksamkeit auf nicht abgedeckte Zeilen erreichten sie einen medianen Line Coverage auf Modulebene von 81 % – eine Verbesserung von 19pp gegenueber der Baseline ohne Feedback.


Wenn der Agent abstuerzt, bleibt der Fortschritt erhalten

LLM-Agenten stuerzen ab. Token-Limit, Netzwerkfehler, Sitzungsabbruch. 527 Funktionen in einer einzigen Sitzung abzuarbeiten ist unmoeglich.

tsma speichert den Fortschritt persistent in .tsma/session.json.

$ tsma status

527 functions
PASS:  246 (46.7%)
DONE:  281 (53.3%)
TODO:    0 (0.0%)

Wenn der Agent bei der 200. Funktion abstuerzt? Ein neuer Agent gibt tsma next ein und macht bei der 201. weiter. session.json ist der Checkpoint.

Mehrere Agenten koennen abwechselnd arbeiten, ohne Konflikte. Jede Funktion ist eine atomare Einheit.


Die Session ist Cache, die Quelldatei ist die Wahrheit

Ein Designprinzip von tsma: Die Session ist Cache, die Quelldatei ist die Source of Truth.

Wenn man eine Testdatei loescht, wird die Funktion wieder zu TODO – selbst wenn session.json sie als PASS fuehrt. Die Session weicht nie von der Realitaet ab.

Prinzip:
  Session.json sagt "PASS"?
  Keine Testdatei vorhanden → TODO
  Quelldatei geaendert → erneute Messung

Anweisungen fuer den LLM-Agenten

Der Agent braucht 6 Zeilen Anweisung:

1. tsma next ausfuehren
2. TODO -- Funktion lesen und Test schreiben
3. Test schlaegt fehl -- Fehler lesen und Test korrigieren
4. Nicht abgedeckte Zweige angezeigt -- Tests fuer diese Zweige hinzufuegen
5. PASS/DONE -- naechste Funktion wird automatisch angezeigt
6. Wiederholen, bis "All functions complete!" erscheint

Der Agent muss nur einen Befehl kennen: tsma next. Den Rest erzwingt das CLI.


Der Zug und die Schienen

Vibe Coding ist ein Zug. Schnell. Aber ohne Schienen entgleist er.

Alle AI-Coding-Tools konzentrieren sich darauf, den Zug schneller zu machen. Groessere Modelle, kluegere Agenten, bessere Prompts. Aber je schneller der Zug wird, desto groesser der Schaden bei einer Entgleisung.

tsma ist die Schiene. Das LLM generiert Tests (Neural), das CLI definiert “bis hierhin und nicht weiter” (Symbolic Constraint). Die Kreativitaet des LLM bleibt unangetastet, aber die Qualitaet des Ergebnisses wird maschinell erzwungen.

Bishertsma
Tests schreibenMensch (langsam) oder LLM (chaotisch)LLM schreibt, CLI verifiziert
Wo anfangen?Mensch entscheidetCLI bestimmt die Reihenfolge
QualitaetspruefungMensch reviewtCLI misst Coverage
FeedbackKeinesNicht abgedeckte Zweige mit Zeilennummern
FortschrittKeinersession.json automatisch

Das LLM generiert frei. Aber es faehrt nur auf der Schiene von tsma next.


Sprachunterstuetzung

SpracheIndexerTest-RunnerCoverage
Gogo/astgo testgo test -coverprofile
TypeScriptregexnpx vitest / npx jestc8 / istanbul
Pythonregexpytestcoverage.py

Go verwendet einen AST-Parser fuer praezise Funktionsextraktion. TypeScript und Python basieren auf regulaeren Ausdruecken.

Generierte Dateien (*_gen.go, *.pb.go), Testdateien und vendor/node_modules werden automatisch vom Indexing ausgeschlossen.


Installation und Ausfuehrung

make install
cd your-legacy-project
tsma next

Das ist alles.

MIT License. github.com/park-jun-woo/tsma


Quellen

  • Schafer, M., Nadi, S., Eghbali, A., & Tip, F. (2023). An Empirical Evaluation of Using Large Language Models for Automated Unit Test Generation. IEEE Transactions on Software Engineering, 50(1), 85–105. arXiv:2302.06527
  • Pizzorno, J. A., & Berger, E. D. (2024). CoverUp: Coverage-Guided LLM-Based Test Generation. arXiv preprint arXiv:2403.16218. arXiv:2403.16218
  • Ryan, G., Jain, S., Shang, M., Wang, S., Ma, X., Ramanathan, M. K., & Ray, B. (2024). Code-Aware Prompting: A Study of Coverage-Guided Test Generation in Regression Setting using LLM. Proceedings of the ACM on Software Engineering (FSE 2024), 1(FSE), 951–971. ACM DL
  • Lemieux, C., Inala, J. P., Lahiri, S. K., & Sen, S. (2023). CodaMOSA: Escaping Coverage Plateaus in Test Generation with Pre-trained Large Language Models. ICSE 2023, 951–963. ACM DL
  • Feathers, M. C. (2004). Working Effectively with Legacy Code. Prentice Hall. ACM DL
  • Besker, T., Martini, A., & Bosch, J. (2018). Technical Debt Cripples Software Developer Productivity. TechDebt 2018, 105–114. ACM DL
  • Stripe. (2018). The Developer Coefficient. PDF
  • U.S. Government Accountability Office. (2019). Information Technology: Agencies Need to Develop Modernization Plans for Critical Legacy Systems. GAO-19-471. GAO
  • Tornhill, A., & Borg, M. (2022). Code Red: The Business Impact of Code Quality. TechDebt 2022, 11–20. arXiv:2203.04374
  • Peng, S., Kalliamvakou, E., Cihon, P., & Demirer, M. (2023). The Impact of AI on Developer Productivity: Evidence from GitHub Copilot. arXiv:2302.06590

Verwandt: Ratchet Pattern – Wie man einen Agenten dazu bringt, die Aufgabe zu Ende zu fuehren – Das Pattern hinter tsma. Warum mechanische Verifikation besser ist als LLM-Urteile.

Verwandt: Modell-IQ ist weniger wichtig als Feedback-Topologie – Warum die Feedback-Struktur die Ergebnisse staerker bestimmt als die Modellleistung.

Änderungsverlauf

  • 2026-05-14: Erstveröffentlichung