Was macht KI-Regressionstests?
Testmuster, die speziell für die KI-gestützte Entwicklung entwickelt wurden, bei der dasselbe Modell Code schreibt und überprüft – wodurch systematische blinde Flecken entstehen, die nur automatisierte Tests abfangen können.
Wann aktivieren
- KI-Agent (Claude Code, Cursor, Codex) hat API-Routen oder Backend-Logik geändert
- Ein Fehler wurde gefunden und behoben – muss ein erneutes Auftreten verhindern
- Projekt hat einen Sandkasten-/Mock-Modus, der für Datenbank-freie Tests genutzt werden kann
- Ausführen von
/bug-checkoder ähnlichen Überprüfungsbefehlen nach Codeänderungen - Mehrere Codepfade vorhanden (Sandkasten vs. Produktion, Feature-Flags usw.)
Das Kernproblem
Wenn eine KI Code schreibt und dann ihre eigene Arbeit überprüft, trägt sie die gleichen Annahmen in beide Schritte. Dies erzeugt ein vorhersehbares Fehlermuster:
KI schreibt Fix → KI überprüft Fix → KI sagt „sieht korrekt aus" → Fehler existiert immer noch
Beispiel aus der Praxis (in der Produktion beobachtet):
Fix 1: notification_settings zur API-Antwort hinzugefügt
→ Vergessen, sie zur SELECT-Abfrage hinzuzufügen
→ KI überprüft und übersehen (gleicher blinder Fleck)
Fix 2: Zur SELECT-Abfrage hinzugefügt
→ TypeScript-Build-Fehler (Spalte nicht in generierten Typen)
→ KI hat Fix 1 überprüft, aber das SELECT-Problem nicht erkannt
Fix 3: Geändert zu SELECT *
→ Produktionspfad gefixt, Sandkastenpfad vergessen
→ KI überprüft und WIEDER übersehen (4. Vorkommen)
Fix 4: Test hat es sofort beim ersten Durchlauf abgefangen BESTANDEN:
Das Muster: Sandkasten-/Produktionspfad-Inkonsistenz ist die #1 KI-eingeführte Regression.
API-Tests im Sandkastenmodus
Die meisten Projekte mit KI-freundlicher Architektur haben einen Sandkasten-/Mock-Modus. Dies ist der Schlüssel zu schnellen, datenbankfreien API-Tests.
Setup (Vitest + Next.js App Router)
// vitest.config.ts
import { defineConfig } from "vitest/config";
import path from "path";
export default defineConfig({
test: {
environment: "node",
globals: true,
include: ["__tests__/**/*.test.ts"],
setupFiles: ["__tests__/setup.ts"],
},
resolve: {
alias: {
"@": path.resolve(__dirname, "."),
},
},
});
// __tests__/setup.ts
// Sandkastenmodus erzwingen — keine Datenbank nötig
process.env.SANDBOX_MODE = "true";
process.env.NEXT_PUBLIC_SUPABASE_URL = "";
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY = "";
Test-Helfer für Next.js API-Routen
// __tests__/helpers.ts
import { NextRequest } from "next/server";
export function createTestRequest(
url: string,
options?: {
method?: string;
body?: Record<string, unknown>;
headers?: Record<string, string>;
sandboxUserId?: string;
},
): NextRequest {
const { method = "GET", body, headers = {}, sandboxUserId } = options || {};
const fullUrl = url.startsWith("http") ? url : `http://localhost:3000${url}`;
const reqHeaders: Record<string, string> = { ...headers };
if (sandboxUserId) {
reqHeaders["x-sandbox-user-id"] = sandboxUserId;
}
const init: { method: string; headers: Record<string, string>; body?: string } = {
method,
headers: reqHeaders,
};
if (body) {
init.body = JSON.stringify(body);
reqHeaders["content-type"] = "application/json";
}
return new NextRequest(fullUrl, init);
}
export async function parseResponse(response: Response) {
const json = await response.json();
return { status: response.status, json };
}
Regressionstests schreiben
Das Kernprinzip: Schreiben Sie Tests für gefundene Fehler, nicht für funktionierenden Code.
// __tests__/api/user/profile.test.ts
import { describe, it, expect } from "vitest";
import { createTestRequest, parseResponse } from "../../helpers";
import { GET, PATCH } from "@/app/api/user/profile/route";
// Den Vertrag definieren — welche Felder MÜSSEN in der Antwort sein
const REQUIRED_FIELDS = [
"id",
"email",
"full_name",
"phone",
"role",
"created_at",
"avatar_url",
"notification_settings", // ← Hinzugefügt, nachdem Fehler ihn als fehlend erkannt hat
];
describe("GET /api/user/profile", () => {
it("gibt alle erforderlichen Felder zurück", async () => {
const req = createTestRequest("/api/user/profile");
const res = await GET(req);
const { status, json } = await parseResponse(res);
expect(status).toBe(200);
for (const field of REQUIRED_FIELDS) {
expect(json.data).toHaveProperty(field);
}
});
// Regressionstest — dieser genaue Fehler wurde 4 Mal von der KI eingeführt
it("notification_settings ist nicht undefined (BUG-R1 Regression)", async () => {
const req = createTestRequest("/api/user/profile");
const res = await GET(req);
const { json } = await parseResponse(res);
expect("notification_settings" in json.data).toBe(true);
const ns = json.data.notification_settings;
expect(ns === null || typeof ns === "object").toBe(true);
});
});
Sandkasten-/Produktions-Parität testen
Die häufigste KI-Regression: Beheben des Produktionspfads, aber Vergessen des Sandkastenpfads (oder umgekehrt).
// Testen, dass Sandkastenantworten dem erwarteten Vertrag entsprechen
describe("GET /api/user/messages (Konversationsliste)", () => {
it("enthält partner_name im Sandkastenmodus", async () => {
const req = createTestRequest("/api/user/messages", {
sandboxUserId: "user-001",
});
const res = await GET(req);
const { json } = await parseResponse(res);
// Dies hat einen Fehler abgefangen, bei dem partner_name
// zum Produktionspfad hinzugefügt, aber nicht zum Sandkastenpfad
if (json.data.length > 0) {
for (const conv of json.data) {
expect("partner_name" in conv).toBe(true);
}
}
});
});
Integration von Tests in den Bug-Check-Workflow
Definition eines benutzerdefinierten Befehls
<!-- .claude/commands/bug-check.md -->
# Fehlerüberprüfung
## Schritt 1: Automatisierte Tests (obligatorisch, kann nicht übersprungen werden)
Führen Sie diese Befehle VOR jeder Codeüberprüfung aus:
npm run test # Vitest-Testsuite
npm run build # TypeScript-Typenprüfung + Build
- Wenn Tests fehlschlagen → als Fehler mit höchster Priorität melden
- Wenn Build fehlschlägt → Typfehler als höchste Priorität melden
- Nur zu Schritt 2 fortfahren, wenn beide bestanden sind
## Schritt 2: Codeüberprüfung (KI-Überprüfung)
1. Konsistenz Sandkasten-/Produktionspfad
2. API-Antwortform entspricht Frontend-Erwartungen
3. Vollständigkeit der SELECT-Klausel
4. Fehlerbehandlung mit Rollback
5. Race-Conditions bei optimistischen Aktualisierungen
## Schritt 3: Für jeden behobenen Fehler einen Regressionstest vorschlagen
Der Workflow
Benutzer: "バグチェックして" (oder "/bug-check")
│
├─ Schritt 1: npm run test
│ ├─ FEHLGESCHLAGEN → Fehler mechanisch gefunden (kein KI-Urteil nötig)
│ └─ BESTANDEN → Fortfahren
│
├─ Schritt 2: npm run build
│ ├─ FEHLGESCHLAGEN → Typfehler mechanisch gefunden
│ └─ BESTANDEN → Fortfahren
│
├─ Schritt 3: KI-Codeüberprüfung (unter Berücksichtigung bekannter blinder Flecken)
│ └─ Ergebnisse gemeldet
│
└─ Schritt 4: Für jede Behebung einen Regressionstest schreiben
└─ Nächste Fehlerüberprüfung fängt ab, ob der Fix bricht
Häufige KI-Regressionsmuster
Muster 1: Sandkasten-/Produktionspfad-Ungleichheit
Häufigkeit: Am häufigsten (beobachtet bei 3 von 4 Regressionen)
// FEHLER: KI fügt Feld nur zum Produktionspfad hinzu
if (isSandboxMode()) {
return { data: { id, email, name } }; // Neues Feld fehlt
}
// Produktionspfad
return { data: { id, email, name, notification_settings } };
// BESTANDEN: Beide Pfade müssen die gleiche Form zurückgeben
if (isSandboxMode()) {
return { data: { id, email, name, notification_settings: null } };
}
return { data: { id, email, name, notification_settings } };
Test, um es abzufangen:
it("Sandkasten und Produktion geben gleiche Felder zurück", async () => {
// In der Testumgebung ist der Sandkastenmodus EINGESCHALTET
const res = await GET(createTestRequest("/api/user/profile"));
const { json } = await parseResponse(res);
for (const field of REQUIRED_FIELDS) {
expect(json.data).toHaveProperty(field);
}
});
Muster 2: SELECT-Klausel-Auslassung
Häufigkeit: Häufig bei Supabase/Prisma beim Hinzufügen neuer Spalten
// FEHLER: Neue Spalte zur Antwort, aber nicht zur SELECT-Klausel hinzugefügt
const { data } = await supabase
.from("users")
.select("id, email, name") // notification_settings nicht hier
.single();
return { data: { ...data, notification_settings: data.notification_settings } };
// → notification_settings ist immer undefined
// BESTANDEN: SELECT * verwenden oder neue Spalten explizit einschließen
const { data } = await supabase
.from("users")
.select("*")
.single();
Muster 3: Fehlerzustandsleck
Häufigkeit: Mittel — beim Hinzufügen von Fehlerbehandlung zu bestehenden Komponenten
// FEHLER: Fehlerzustand gesetzt, aber alte Daten nicht gelöscht
catch (err) {
setError("Fehler beim Laden");
// Reservierungen zeigt immer noch Daten vom vorherigen Tab!
}
// BESTANDEN: Verwandten Zustand bei Fehler löschen
catch (err) {
setReservations([]); // Veraltete Daten löschen
setError("Fehler beim Laden");
}
Muster 4: Optimistische Aktualisierung ohne ordnungsgemäßes Rollback
// FEHLER: Kein Rollback bei Fehler
const handleRemove = async (id: string) => {
setItems(prev => prev.filter(i => i.id !== id));
await fetch(`/api/items/${id}`, { method: "DELETE" });
// Wenn API fehlschlägt, ist das Element aus der UI verschwunden, aber noch in der DB
};
// BESTANDEN: Vorherigen Zustand erfassen und bei Fehler Rollback durchführen
const handleRemove = async (id: string) => {
const prevItems = [...items];
setItems(prev => prev.filter(i => i.id !== id));
try {
const res = await fetch(`/api/items/${id}`, { method: "DELETE" });
if (!res.ok) throw new Error("API-Fehler");
} catch {
setItems(prevItems); // Rollback
alert("Löschen fehlgeschlagen");
}
};
Strategie: Testen, wo Fehler gefunden wurden
Streben Sie nicht nach 100% Abdeckung. Stattdessen:
Fehler gefunden in /api/user/profile → Test für Profil-API schreiben
Fehler gefunden in /api/user/messages → Test für Nachrichten-API schreiben
Fehler gefunden in /api/user/favorites → Test für Favoriten-API schreiben
Kein Fehler in /api/user/notifications → Keinen Test schreiben (noch nicht)
Warum dies bei der KI-Entwicklung funktioniert:
- KI neigt dazu, die gleiche Kategorie von Fehlern wiederholt zu machen
- Fehler treten in komplexen Bereichen auf (Authentifizierung, Multi-Pfad-Logik, Zustandsverwaltung)
- Einmal getestet, kann diese genaue Regression nicht mehr auftreten
- Die Testanzahl wächst organisch mit Fehlerbehebungen — keine verschwendete Mühe
Kurzreferenz
| KI-Regressionsmuster | Teststrategie | Priorität |
|---|---|---|
| Sandkasten-/Produktions-Ungleichheit | Gleiche Antwortform im Sandkastenmodus bestätigen | Hoch |
| SELECT-Klausel-Auslassung | Alle erforderlichen Felder in der Antwort bestätigen | Hoch |
| Fehlerzustandsleck | Zustandsbereinigung bei Fehler bestätigen | Mittel |
| Fehlendes Rollback | Zustandswiederherstellung bei API-Fehler bestätigen | Mittel |
| Typumwandlung maskiert null | Bestätigen, dass Feld nicht undefined ist | Mittel |
TUN / NICHT TUN
TUN:
- Schreiben Sie Tests sofort nach dem Finden eines Fehlers (wenn möglich vor der Behebung)
- Testen Sie die Form der API-Antwort, nicht die Implementierung
- Führen Sie Tests als ersten Schritt jeder Fehlerüberprüfung aus
- Halten Sie Tests schnell (< 1 Sekunde insgesamt mit Sandkastenmodus)
- Benennen Sie Tests nach dem Fehler, den sie verhindern (z. B. „BUG-R1 Regression")
NICHT TUN:
- Schreiben Sie Tests für Code, der noch nie einen Fehler hatte
- Vertrauen Sie auf die KI-Selbstüberprüfung als Ersatz für automatisierte Tests
- Überspringen Sie Sandkastenpfad-Tests, weil „es nur Mock-Daten sind"
- Schreiben Sie Integrationstests, wenn Unit-Tests ausreichen
- Streben Sie nach Abdeckungsprozentsatz — streben Sie nach Regressionsverhinderung