Gewinne:
- Fähigkeit, zu verhindern, dass künstliche Intelligenz fehlerhaftes Verhalten als „richtig“ akzeptiert, indem der Erwartungswert in Unit-Tests unabhängig von der Akzeptanzregel berechnet wird
- Fähigkeit, schnelle, unabhängige und wiederholbare Tests zu drucken, indem AAA- und FIRST-Prinzipien angewendet und externe Abhängigkeiten simuliert werden
- Fähigkeit, Tests mit Mutation (Code-Breaking) zu testen und schwer zu testenden Code als Designgeruch zu erkennen
Die größte und schnellste Ebene der Testpyramide ist das Unit-Testen – ein Test, der eine Funktion oder einen kleinen Codeabschnitt isoliert von allem anderen überprüft. Tausende Unit-Tests laufen in Sekundenschnelle und erkennen einen Fehler, während der Code noch auf dem Bildschirm des Entwicklers angezeigt wird. Künstliche Intelligenz (KI) eignet sich vielleicht am besten für die Erstellung von Unit-Tests: Geben Sie ihr eine Funktion, erstellt KI Dutzende Tests. Doch genau aus dieser Bequemlichkeit entsteht die größte Falle: KI produziert leicht Tests, die „grün leuchten, aber nichts verifizieren“ oder das aktuelle (vielleicht fehlerhafte) Verhalten des Codes als „richtig“ akzeptieren. In dieser Einheit erfahren Sie, wie Sie wirklich schützende Unit-Tests mit KI schreiben und welche Beziehung zwischen testbarem Code und KI besteht.
Eigenschaften eines guten Unit-Tests: ZUERST
Gute Unit-Tests folgen den FIRST-Prinzipien: Schnell, unabhängig (Tests sollten nicht voneinander abhängig sein), wiederholbar (wiederholbar – dasselbe Ergebnis in jeder Umgebung), selbstvalidierend (eindeutig bestanden/nicht bestanden), zeitnah (pünktlich). Erinnern Sie sich an diese Grundsätze, wenn Sie KI Tests durchführen lassen. Bitten Sie ausdrücklich darum, dass der Test nicht von der Außenwelt (tatsächliche Datenbank, Netzwerk, Uhr) abhängt, um „unabhängig“ und „wiederholbar“ zu sein.
AAA-Muster und ausdrucksstarke Aussage
Ein solider Unit-Test folgt der AAA-Struktur: Arrange (vorbereiten – Eingaben und Abhängigkeiten einrichten), Act (ausführen – die zu testende Funktion aufrufen), Assert (validieren – das Ergebnis mit dem erwarteten Wert vergleichen). Der entscheidende Punkt ist die Behauptung. Der häufigste Fehler, den KI macht, besteht darin, die Behauptung aus der Ausgabe des zu testenden Codes abzuleiten – die Logik „Was auch immer der Code zurückgibt, ist wahr“. Dies macht den Test bedeutungslos. Der richtige Weg besteht darin, den Erwartungswert unabhängig zu ermitteln (aus den Akzeptanzkriterien manuell berechnen).
Achtung: Wenn Sie der KI mitteilen, „einen Test für diese Funktion zu schreiben“, führt die KI möglicherweise die Funktion aus und schreibt ihre Ausgabe als „erwartet“. Dieser Test besteht auch dann, wenn die Funktion falsch ist. Sagen Sie stattdessen: „Sie berechnen die erwarteten Ergebnisse gemäß diesen Regeln und verweisen nicht auf die aktuelle Ausgabe der Funktion.“
Mocks, Stubs und Abhängigkeiten
Unit-Tests erfordern Isolation. Wenn Ihre Funktion von einer Datenbank oder API abhängt, werden diese beim Testen durch Scheinobjekte (Mock/Stub – ein kontrollierter Dummy-Ersatz für die tatsächliche Abhängigkeit) ersetzt. Dies macht den Test schnell, unabhängig und reproduzierbar. KI kann Scheininstallationen erstellen; Aber hüten Sie sich vor übermäßiger Verspottung: Wenn Sie alles verspotten, überprüft der Test nur, „was die Verspottung zurückgibt“, nicht die eigentliche Logik. Balance: Emulieren Sie die Außenwelt und führen Sie die tatsächliche zu testende Logik aus.
Testbarkeit und KI
Es gibt ein interessantes Feedback: Code, der schwer zu testen ist, ist oft schlecht gestalteter Code. Wenn die KI Schwierigkeiten hat, Tests für eine Funktion zu schreiben (zu viele Abhängigkeiten, versteckter globaler Status, Nebenwirkungen), ist das ein Designgeruch. Die Frage an die KI: „Wie würden Sie diesen Code umgestalten, um ihn testbar zu machen?“ führt sowohl zu besseren Tests als auch zu besserem Code.
Parametrisierte Tests und Datenvielfalt
Jedes Mal einen separaten Test zu schreiben, um dieselbe Regel mit unterschiedlichen Eingaben zu überprüfen, ist sowohl mühsam als auch schwierig zu warten. Parametrisiertes Testen – eine Struktur, die wiederholt dieselbe Testlogik auf einer Liste von Eingaben und erwarteten Ergebnissen ausführt – eliminiert diese Wiederholung: Ein einzelner Testkörper wird mit Dutzenden von Eingabepaaren gefüttert. KI ist sehr effizient bei der Erstellung dieser Eingabe-erwarteten Ergebnistabellen, wenn Sie ihr Ihre Akzeptanzregeln geben; Insbesondere werden Grenzwerte und Äquivalenzklassen systematisch tabellarisch aufgeführt.
Aber auch hier gibt es eine Falle: Die KI neigt dazu, die erwarteten Ergebnisse in der generierten Tabelle aus dem zu testenden Code abzuleiten. Dieser Fehler ist bei parametrisierten Tests noch gefährlicher, da eine einzige falsche Logik Dutzende Zeilen ungültig macht. Lassen Sie daher die erwartete Ergebnisspalte immer selbstständig gemäß der Akzeptanzregel berechnen und validieren Sie mindestens einige Zeilen manuell. Bitten Sie auch um eine Beschreibungsspalte „Was stellt jede Zeile dar“; Wenn also eine Zeile unterbrochen wird, sehen Sie sofort, welcher Status unterbrochen ist.
Tipp: Fügen Sie der parametrisierten Testtabelle absichtlich eine „Trap-Zeile“ hinzu – das heißt, Sie geben das Ergebnis wissentlich falsch ein. Wenn diese Linie beim Ausführen des Tests nicht rot wird, überprüft Ihr Test diese Situation nicht wirklich. Dies ist eine schnelle Scheinüberprüfung.
Schwache Eingabeaufforderung / Starke Eingabeaufforderung
Schwach: „Schreiben Sie einen Unit-Test für diese Funktion.“
Stark: Schreiben Sie [Sprache/Framework]-Komponententests für die Funktion „taxCalculate(amount, rate)“. Akzeptanzregel: Ergebnis = Betrag * Satz, auf 2 Dezimalstellen gerundet; überprüft. Externe Abhängigkeit „Nein.“
Leistungsstarke Eingabeaufforderung; Es gibt die Akzeptanzregel, die unabhängige Erwartungswerterwartung, die Struktur und Randfälle an. Somit wird der Test zum Hüter der Regel und nicht zum Spiegel des Codes.
Qualitätstabelle für Unit-Tests
Symptom
Schlechter Test (Fake-Trust)
guter Test
behaupten
Keine oder „nicht null“
Erwarteter konkreter Wert
Erwartete Wertquelle
Ausgabe der Funktion
Akzeptanzregel / manuelle Berechnung
Sucht
Tatsächliche DB/Netzwerk/Stunde
Isoliert mit Mock/Stub
Randfall
Nur glücklicher Weg
Grenze, negativ, Fehler
Wenn Sie den Code knacken
bleibt grün
wird rot
Name
test1, testMethod
beschreibt die Regel, die es bestätigt
Vier kopierbare Vorlagen
1) Regelgesteuerter Unit-Test:
Ihre Rolle: Senior Software Test Engineer. Schreiben Sie einen Unit-Test für die folgende Funktion mit [Sprache/Framework]: [Signatur]. Akzeptanzregeln: [Regeln]. - Verwenden Sie eine AAA-Struktur. - Berechnen Sie die erwarteten Werte manuell gemäß DIESEN Regeln. Verweisen Sie NICHT auf die aktuelle Ausgabe der Funktion. - Decken Sie den Grenzwert, den negativen Pfad, den Fehler und den glücklichen Pfad mit separaten Tests ab. - Lassen Sie jeden Testnamen die Regel beschreiben, die er überprüft. - Scheinen Sie externe Abhängigkeiten; Sorgen Sie dafür, dass die eigentliche Logik funktioniert.
2) Mutationsresistenzkontrolle:
Schauen Sie sich diese Unit-Tests an. Listen Sie 5 kleinere Änderungen auf, die ich am zu testenden Code vornehmen könnte (ein - anstelle eines +, ein >= anstelle eines >, eine Grenzverschiebung) und sagen Sie mir für jeden dieser Tests, WELCHER dieser Tests rot angezeigt wird? Wenn keine zurückgegeben werden, ist der Test unzureichend. Code + Tests: [Einfügen]
3) Überprüfung der Testbarkeit:
Warum ist es schwierig, einen Unit-Test für diese Funktion zu schreiben? Versteckte Sucht, globaler Status, Nebenwirkungen, gibt es viele Verantwortlichkeiten? Schlagen Sie eine minimale Umgestaltung vor, um es testbar zu machen. Verhalten nicht ändern. Code: [einfügen]
4) Unvollständiger Abschluss des Szenarios:
Die folgenden Funktionen und verfügbaren Tests werden angegeben. Listen Sie auf, welches Verhalten/welcher Randfall NIE getestet wurde (Bereichslücke) und fügen Sie für jedes Verhalten einen Test hinzu. Funktion+Tests: [Einfügen]
drei Mini-Koffer
Fall 1 – Testen Sie die Spiegelung des Codes. Ein Entwickler ließ von der KI einen Test für die Rundungsfunktion schreiben; 10 Tests waren grün. Tatsächlich rundete die Funktion in die falsche Richtung, aber die KI hatte die erwarteten Werte aus der Ausgabe der Funktion übernommen, sodass die Tests den Fehler als „wahr“ betrachteten. Bei der manuellen Berechnung der erwarteten Werte mit der „regelgesteuerten“ Vorlage wurden 4 Tests rot und der tatsächliche Fehler wurde aufgedeckt.
Fall 2 – Der Wert der Mutationskontrolle. Ein Team stützte sich auf 45 Unit-Tests. Versuchte 20 kleinere Änderungen am Code mit einer „Mutationsrobustheitsprüfung“; Tests haben nur 11 von ihnen gefangen. Die restlichen 9 Störungen verliefen lautlos. Das Team verstärkte schwache Tests; Durch diese erweiterten Tests wurde in der nächsten Version ein tatsächlicher Berechnungsfehler festgestellt.
Fall 3 – Untestbarkeit ist ein Designgeruch. Die KI konnte keine Tests für eine Bestellfunktion schreiben, sie benötigte ständig die reale Datenbank. Die Vorlage „Testability Review“ zeigte, dass die Funktion den Datenbankzugriff einbettete. Als die Abhängigkeitsinjektion entfernt wurde, konnten Tests geschrieben werden und der Code wurde sauberer.
Häufige Fehler
- Ableiten des erwarteten Werts aus dem Code. Die KI akzeptiert die Funktionsausgabe als „richtig“; Test, der fehlerhaften Code bestätigt.
- Testen Sie ohne Assert oder mit trivialem Assert. „Er hat keinen Fehler gemacht, er hat bestanden“-Logik; Es bestätigt nichts.
- Extremer Spott. Alles verspotten und nur testen, was der Spott zurückgibt; Echte Logik wird nicht getestet.
- Einfach der glückliche Weg. Umgehen von Grenz-, Negativ- und Fehlerzuständen.
- Nicht testen, indem der Code gebrochen wird. Vertrauen Sie auf Grün, ohne auf Mutationen zu prüfen.
- Ignorieren der Unprüfbarkeit. Schlechtes Design nicht erkennen und beheben, anstatt harte Tests voranzutreiben.
Zusammenfassend
Unit-Tests sind die schnellste und größte Ebene der Testpyramide. Es fängt den Fehler im günstigsten Moment auf. KI ist sehr gut in der Lage, Unit-Tests zu erstellen, aber ihre größte Gefahr besteht darin, Tests zu schreiben, die falsches Verhalten als „richtig“ annehmen, indem sie den erwarteten Wert aus dem Code selbst ableiten. Lösung: Geben Sie die Akzeptanzregeln an, lassen Sie die erwarteten Werte manuell berechnen, setzen Sie die AAA- und FIRST-Prinzipien durch, verspotten Sie die Außenwelt und führen Sie die eigentliche Logik aus und testen Sie jeden Test durch Mutation (Brechen des Codes). Code, der schwer zu testen ist, ist ein Designzeichen, das repariert werden muss.
Anwendungsaufgabe
Wählen Sie eine Funktion aus, die eine Geschäftsregel aus Ihrem eigenen Projekt enthält. Schreiben Sie Akzeptanzregeln und lassen Sie die KI Tests mit der Vorlage „regelgesteuerte Unit-Tests“ schreiben. Lassen Sie die Erwartungswerte manuell berechnen. Wenden Sie dann die „Mutationsrobustheitsprüfung“ an: Machen Sie mindestens fünf kleine Unterbrechungen im Code und messen Sie, wie viele Tests rot werden. Neuen Test für nicht erkannte Korruptionen hinzufügen. Geben Sie an, wie viele Störungen festgestellt wurden (z. B. Mutationsbewertung).
Checkliste
- [ ] Ich habe die Akzeptanzregeln angegeben und die Erwartungswerte manuell berechnen lassen.
- [ ] Ich habe sichergestellt, dass die Tests nicht den erwarteten Wert aus dem Code abgeleitet haben.
- [ ] Ich habe unabhängige Tests gemäß den AAA- und FIRST-Richtlinien durchgeführt.
- [ ] Ich habe die externen Abhängigkeiten verspottet und die eigentliche Logik ausgeführt.
- [ ] Ich habe Grenz-, Negativ- und Fehlerfälle behandelt.
- [ ] Durch das Brechen des Codes (Mutation) habe ich bewiesen, dass die Tests tatsächlich schützen.