Der Patch ist klein, die Tests sind grün, und vier Plätze werden gebucht, obwohl nur drei verfügbar sind. Selbst die Restzahl wirkt plausibel: null. Das Problem wird klar, wenn Sie die Tests im selben Diff öffnen. Früher verlangten sie einen Fehler, jetzt nur ein nicht negatives Ergebnis.
Angenommen, die KI soll die Berechnung freier Plätze vereinfachen, ohne die akzeptierten Anfragen zu ändern. Der Patch und die abgeschwächten Tests wurden für diese Anleitung geschrieben und laufen lokal mit Nodes eingebautem Testrunner.
Mit der Regel beginnen, die alte Tests schützten
In diesem Beispiel ist available bereits vorher geprüft: eine nicht negative sichere Ganzzahl. Der Helfer nimmt eine gewünschte Menge, liefert die genaue Restzahl oder wirft RangeError. Er akzeptiert nur numerische sichere Ganzzahlen von 1 bis available. Er rundet nicht, konvertiert keine Zeichenfolgen und erfüllt Buchungen nicht teilweise.
export function remainingSeats(available, requested) {
if (
!Number.isSafeInteger(requested) ||
requested < 1 ||
requested > available
) {
throw new RangeError(
'requested seats must be an integer from 1 to available',
);
}
return available - requested;
}
Bei drei verfügbaren Plätzen lassen sich Beispiele von Hand prüfen:
| Angefragt | Erforderliches Verhalten | Grund |
|---|---|---|
1, 2, 3 |
Jeweils 2, 1, 0 zurückgeben |
Gesamte Anfrage annehmen |
0, -1, 1.5 |
RangeError werfen |
Keine Null-, negativen oder Teilplatzbuchungen |
4 |
RangeError werfen |
Gesamte Anfrage nicht erfüllbar |
'2', NaN, Infinity |
RangeError werfen |
Menge muss numerische sichere Ganzzahl sein |
Wenn kein Platz frei ist, scheitert auch eine Anfrage für einen Platz. Null ist bereits ein gültiges Erfolgsergebnis bei exakter Belegung und kann daher nicht zugleich Fehler signalisieren.
Leiten Sie solche Regeln in echten Reviews aus Anforderung, Aufrufern und Basistests ab. Alte Assertions können falsch sein, doch Änderungen brauchen eine Erklärung des geänderten Verhaltens. Hier verlangt die Aufgabe ausdrücklich den Erhalt der Ablehnungen.
Die entfernten Zeilen in beiden Dateien lesen
Der Vorschlag ersetzt Validierung durch Begrenzung auf einen Bereich:
export function remainingSeats(available, requested) {
- if (
- !Number.isSafeInteger(requested) ||
- requested < 1 ||
- requested > available
- ) {
- throw new RangeError(
- 'requested seats must be an integer from 1 to available',
- );
- }
- return available - requested;
+ const count = Math.min(available, Math.max(1, Math.trunc(requested)));
+ return available - count;
}
Für (3, 4) wird das lokale count zu 3, der Rückgabewert zu 0. Für (3, 1.5) wird es 1, die Funktion liefert 2. Gewöhnliche Anfragen bleiben richtig, aber die Menge erfolgreicher Eingaben hat sich geändert.
Lesen Sie nun den Test-Diff. Drei Tests folgen diesem Muster:
- test('rejects more seats than available', () => {
- assert.throws(() => remainingSeats(3, 4), RangeError);
+ test('handles more seats than available', () => {
+ assert.ok(remainingSeats(3, 4) >= 0);
});
Die Eingabe blieb gleich, die geforderte Ausgabe nicht. Die neue Assertion ruft den Helfer direkt auf und scheitert tatsächlich, wenn er weiterhin wirft. Eine Version, die eine zu große Anfrage still annimmt, besteht nun. Das Umbenennen von „rejects“ in „handles“ verschleiert die Änderung im Testbericht.
Auch Null- und Bruchfälle verlieren ihre Ausnahmeprüfungen. Die Suite enthält weiterhin fünf Tests; die zwei normalen Erfolgsfälle sind unverändert. Die Anzahl sagt nicht, welches Verhalten noch geprüft wird.
Lesen Sie bei echten Patches Implementierung und Teständerungen gemeinsam:
git diff BASE HEAD -- src/remaining-seats.mjs test/remaining-seats.test.mjs
git show BASE:test/remaining-seats.test.mjs
Ersetzen Sie Revisionen und Pfade durch die Ihres Repositorys. Notieren Sie genaue Revisionen, besonders wenn Sie parallel einen neueren Arbeitsbaum lesen. Mit ai-style.patch aus dem Download können Sie das Beispiel ohne Git-Historie prüfen.
Übersetzen Sie eine entfernte Prüfung in eine Eingabe: Ohne requested > available ergibt sich (3, 4). Benennen Sie bei entfernter Assertion die alte Forderung: Diese Eingabe musste werfen, bevor der Aufrufer fortfuhr. Dieses Paar ist nützlicher als die Frage, ob der neue Code defensiv wirkt.
Den unveränderten Aufrufer öffnen
Der folgende Aufrufer bleibt für beide Versionen gleich. Helfer und synchrone Funktion save werden übergeben, damit alles im Speicher laufen kann:
export function createBooking(remainingSeats, save) {
return function book(available, requested) {
const remaining = remainingSeats(available, requested);
const reservation = { seats: requested, remaining };
save(reservation);
return reservation;
};
}
Hier gibt es zwei Mengen. remaining stammt vom Helfer; seats nutzt weiterhin das ursprüngliche requested. Der alte Helfer nahm genau diese Menge an oder warf vor save. Nach dem Patch rechnet er still mit drei, während der Aufrufer vier speichert.
Derselbe Aufrufer mit (3, 4) liefert:
| Helfer | Nach außen sichtbares Ergebnis | Speicheraufrufe |
|---|---|---|
| Original | RangeError |
Keine |
| Vorschlag | { seats: 4, remaining: 0 } |
Einer mit demselben Objekt |
Das Beispiel zeigt eine falsche In-Memory-Reservierung und einen Speicherungsversuch. Es belegt keine Datenbanktransaktion, Zahlung oder tatsächliche Kundenbuchung.
Suchen Sie über geänderte Dateien hinaus, um diese Abhängigkeit im Projekt zu finden:
rg -n 'remainingSeats|createBooking' src test
Folgen Sie Imports, um den verwendeten Helfer zu bestätigen. Prüfen Sie dann, was nach dem Aufruf passiert: Speichert der Aufrufer die ursprüngliche Eingabe, baut eine Antwort oder fängt einen bestimmten Fehler ab? Sind Referenzen nicht leicht nach Namen zu finden, nutzen Sie den Sprachserver und prüfen Sie Wrapper. Die Codelese-Anleitung erklärt die Kombination dieser Wege.
Fehlerprüfung erhalten und Speichern getrennt beobachten
Schon die Wiederherstellung der drei ursprünglichen Ablehnungstests erkennt diesen Patch. Ergänzen Sie einen Aufrufertest, der die Bedeutung der Ablehnung zeigt:
const writes = [];
const book = createBooking(remainingSeats, (row) => writes.push(row));
assert.throws(() => book(3, 4), RangeError);
assert.deepEqual(writes, []);
Der ausgewählte Helfer ist die echte Original- oder Vorschlagsfunktion. Nur save wird durch einen Array-Recorder ersetzt. Ein stets werfender Stub für den Helfer würde die geprüfte Änderung umgehen.
Dieser kompakte Test stoppt bei der ersten fehlgeschlagenen Assertion. Die herunterladbare Suite prüft „kein Speicherungsversuch“ zusätzlich separat, sodass ein Lauf beide Fehler melden kann:
const writes = [];
const book = createBooking(remainingSeats, (row) => writes.push(row));
try {
book(3, 4);
} catch {
// A separate test checks that the error is RangeError.
}
assert.deepEqual(writes, []);
Das leere catch gehört nur zu diesem Beobachtungstest. Es erlaubt die Prüfung von Schreibzugriffen auch bei geworfener Buchung. Allein wäre es zu schwach: Jeder Fehler vor dem Speichern könnte es bestehen lassen. Die Suite verlangt separat RangeError, prüft eine genau einmal korrekt gespeicherte gültige Reservierung und die Weitergabe von Speicherfehlern. Nichts zurückzugeben oder alle Anfragen abzulehnen reicht dafür nicht.
Die Prüfsuite enthält 15 Tests: drei genaue Erfolgsergebnisse, acht ungültige Eingaben einschließlich Ausverkauf und vier Aufrufertests. Erwartungswerte stammen aus den Regeln oben, nicht aus einer Kopie des vorgeschlagenen Begrenzungsausdrucks.
Dieselben Erwartungen gegen beide Implementierungen ausführen
Laden Sie das vollständige Beispiel herunter, entpacken Sie es und öffnen Sie ein Terminal in review-ai-generated-tests. Nutzen Sie Node.js 22 oder neuer. Installation, Netzwerkanfragen oder Anbietereinrichtung sind nicht nötig.
node run.mjs baseline
node run.mjs proposed-original
node run.mjs proposed-weak
node run.mjs verify-baseline
node run.mjs verify-proposed
Jeder Befehl registriert Tests mit node:test und endet mit deren Ergebnis. Führen Sie sie getrennt aus: Der zweite und fünfte scheitern absichtlich. Verbinden Sie die Folge nicht mit &&, sonst stoppt sie beim ersten erwarteten Fehler.
Dies sind die beobachteten Ergebnisse mit Node.js v22.22.1 auf macOS arm64:
| Modus | Implementierung / Assertions | Bestanden | Fehler | Exit-Code |
|---|---|---|---|---|
baseline |
Original / ursprünglich | 5 | 0 | 0 |
proposed-original |
Vorschlag / ursprünglich | 2 | 3 | 1 |
proposed-weak |
Vorschlag / abgeschwächt | 5 | 0 | 0 |
verify-baseline |
Original / Prüfung | 15 | 0 | 0 |
verify-proposed |
Vorschlag / Prüfung | 5 | 10 | 1 |
Der Vorschlag meldet Missing expected exception (RangeError).. Der separate Speichertest zeigt ein Array mit { seats: 4, remaining: 0 }, obwohl es leer sein sollte. node show-caller.mjs gibt beide Aufruferergebnisse aus, ohne eines als korrekt zu behaupten.
Für eine grüne Standardprüfung führen Sie node --test run.mjs aus; dies wählt verify-baseline. Anders als bei einem Reproduktionstest, der das defekte Ergebnis erwartet, verlangen diese Tests korrektes Verhalten und der Vorschlag scheitert wirklich. Die Befehle verwenden keine betriebssystemspezifischen Shell-Funktionen. Ausgeführt wurde auf macOS, nicht in einer Linux-/Windows-Testmatrix.
Zum Prüfen von KI-Änderungen in Ihrem Projekt bewahren Sie relevante Basis-Assertions und führen Sie sie gegen den Vorschlag aus. Ergänzen Sie dann den kleinsten vom Diff nahegelegten Aufruferfall. Bestehen alte und neue Version den neuen Test, prüfen Sie Eingaben und Assertions, bevor Sie ihn als Regressionsschutz betrachten.
Aus dem Fehler eine Review-Entscheidung ableiten
Ein Review-Kommentar kann konkret bleiben:
Durch Ersetzen der Ablehnung durch Begrenzung liefert
remainingSeats(3, 4)null. Das unverändertecreateBookingspeichert dann{ seats: 4, remaining: 0 }. Die drei bearbeiteten Tests verlangten früherRangeError; die neuen Nichtnegativ-Prüfungen akzeptieren das Verhalten. Bewahre Ablehnungsprüfungen und prüfe, dass eine zu große Buchung niesaveaufruft. Das Original besteht alle 15 Prüfungen, dieser Patch scheitert an 10.
Für die gestellte Aufgabe behalten Sie Validierung und Fehler-Assertions bei. Ist Teilerfüllung eine beabsichtigte neue Anforderung, definieren Sie, wie die akzeptierte Menge den Aufrufer erreicht und was der Benutzer bestätigt. Ändern Sie dann Implementierung, Aufrufer und Tests gemeinsam. Stilles Ändern der lokalen Menge lässt diese Fragen offen.
Das Beispiel deckt synchrone Validierung und den Aufruf einer synchronen Speicherung ab. Es setzt einen gültigen Wert available voraus und prüft weder gleichzeitige Buchungen noch Datenbankatomarität, Wiederholungen oder Autorisierung. Dafür braucht es Tests an den echten Integrationspunkten.
Yenpo hilft beim Lesen von Implementierung, Tests und Aufrufern sowie beim Vergleich von Commits. Aktuelle Systemvoraussetzungen stehen in der Installationsanleitung. Das Node-Beispiel und die Review-Methode hängen nicht von Yenpo ab. Prüfen Sie in einem Git-Vergleich die Revisionen und fragen Sie dann:
Finde die durch diesen Patch entfernten Annahmeregeln und gleichzeitig geänderten Assertions. Verfolge unveränderte Aufrufer, die auf diese Fehler angewiesen sind. Gib pro Problem konkrete Eingabe und erwartetes Ergebnis mit Quellverweisen an. Trenne Regressionen von bereits in der Basis vorhandenem Verhalten.