Testdesign
Die Fälle entscheiden, was die Suite abfangen kann. Alles danach — die Testumgebung, der Runner, die Zählung — führt diese Entscheidung nur aus.
Die Momente, die dieses Skill ersetzt
| Kurz vor … | Stattdessen … |
|---|---|
| den Happy Path schreiben und aufhören | den Eingaberaum durchgehen: für jeden Parameter seine Klassen und seine Grenzen |
| Fälle aus der Implementierung ableiten | sie aus der Spezifikation ableiten, und die Implementierung überraschen lassen |
| mit einem komfortablen Wert testen | den letzten Wert innerhalb und den ersten Wert außerhalb jeder Grenze testen |
| die Grenze testen, die die Spezifikation nennt | jeder Bereich hat zwei Enden; das im Satz nicht genannte ist immer noch eine Grenze |
| die Rollen aufzählen, die die Spezifikation auflistet | den Aufrufer hinzufügen, den sie vergessen hat: keine Rolle, nicht authentifiziert, nicht zugewiesen |
| eine Bedingung ausgehend vom Happy Path variieren | die Entscheidungstabelle erstellen und die Regeln abdecken, bei denen zwei Bedingungen gleichzeitig fehlschlagen |
| eine Zustandstabelle zeichnen und weitermachen | in jede Zeile eine Test-ID setzen; am meisten in die Zeile, die „nicht erlaubt“ sagt |
| „abgelehnt, oder akzeptiert sofern …“ als erwartetes Ergebnis schreiben | ein Ergebnis pro Fall; eine Spezifikation, die sich nicht entscheiden kann, ist eine offene Frage, kein Test |
| Fehlerpfade als unwahrscheinlich überspringen | jeder Fehlermodus ist eine Klasse: ungültige Eingabe, fehlende Ressource, verweigert, Zeitüberschreitung, halb fertig |
| einen Pfad ohne Test, mit einem Überspring-Marker oder einem unbehaupteten Platzhalter unimplementiert lassen | einen Test schreiben, dass der Pfad heute als unimplementiert zurückgewiesen wird; er besteht jetzt und wird rot an dem Tag, an dem ihn jemand baut (weiter unten) |
| eine Funktion nach ihrem Hauptablauf testen | die alternativen und Ausnahmeabläufe aus dem Anwendungsfall ablesen; jeder ist eine Klasse |
| eine Suite durch Lesen bewerten | sie gegen die Spezifikation zählen: Klassen, beide Grenzen, Regeln, Übergänge |
| einen fünften Test zu einer abgedeckten Klasse hinzufügen | ihn für eine nicht abgedeckte Klasse ausgeben — der fünfte kostet Laufzeit und bringt keine neue Abdeckung |
Die Spezifikation angreifen, nicht die Implementierung
Ein Test, der durch Lesen des Codes geschrieben wurde, behauptet, was der Code tut. Er besteht bei Ankunft, kodiert die aktuellen Fehler als Erwartungen, und sein Fehlschlagen nach einer Änderung sagt „der Code hat sich geändert“, was bereits bekannt war. Dies ist gemessen, nicht vermutet: bei 24 Java-Repositories neigten LLM-generierte Orakel dazu, das tatsächliche Verhalten des Programms einzufangen und nicht sein erwartetes Verhalten (Konstantinou, Degiovanni, Papadakis, arXiv:2410.21136).
Leiten Sie aus dem ab, was die Sache tun soll — der Spezifikation, dem Drahtformat, dem Vertrag — und führen Sie es erst dann aus. Die eine legitime Ausnahme ist der Charakterisierungstest, der bewusst das aktuelle Verhalten festhält, und er ist als solcher markiert, damit niemand später einen festgehaltenen Fehler mit einer Anforderung verwechselt.
Ein nützlicher Hinweis: Wenn jeder Test beim ersten Lauf grün war, wurde die Suite aus der Implementierung abgeleitet, unabhängig von der Absicht.
Äquivalenzklassen: Klassen zählen, nicht Tests
Eingaben, die der Code nicht unterscheiden kann, bilden eine Klasse, und ein Test pro Klasse ist ausreichend — der zweite bis fünfte kostet Laufzeit und beweist nichts Neues. Die Disziplin wirkt in beide Richtungen: keine Klasse ungedeckt, keine Klasse versehentlich doppelt abgedeckt.
Eine Suite mit siebzehn Tests wirkt gründlich. Ob sie es ist, hängt davon ab, in wie viele Klassen diese siebzehn fallen, und diese Zahl erscheint in der Ausgabe keines Runners. Sie muss von Hand gegen den Eingaberaum gezählt werden — was ein Testplan ist.
Die Klassen, die die Spezifikation auflistet, sind die einfache Hälfte. Eine Rollentabelle mit drei Zeilen hat eine vierte Klasse, die Anfrage, die zu keiner davon passt, und es ist die, die eine aus der Tabelle gebaute Suite nie enthält. Schreiben Sie für jeden Parameter die ungültigen Klassen neben die gültigen, bevor Sie einen Fall schreiben: falscher Typ, fehlend, außerhalb jedes aufgeführten Werts, der Aufrufer ohne jegliche Rechte.
Der Lehrplan formuliert dies als Regel und nicht als Gewohnheit: Bei der Äquivalenzklassenbildung sind die Abdeckungselemente die Partitionen, 100 % bedeutet jede identifizierte Partition getestet „einschließlich ungültiger Partitionen“, und die Partitionen „dürfen sich nicht überlappen und müssen nicht-leere Mengen sein“ (ISTQB CTFL v4.0.1 §4.2.1). Mit mehreren Parametern nennt es das schwächste Kriterium Each Choice — jede Partition jedes Parameters einmal, Kombinationen ignoriert — was das Niveau ist, das die meisten Suiten erreichen, ohne seinen Namen zu kennen, und wo unten die Entscheidungstabelle beginnt.
Grenzen, denn dort liegen die Fehler
Um-eins-Versatz ist der häufigste arithmetische Fehler,
und er ist überall außer am Rand unsichtbar.
Das Paar, das an jeder Grenze zählt, ist der Grenzwert und sein nächster Nachbar über der Linie,
was die 2-Wert-Grenzwertanalyse ist (CTFL v4.0.1 §4.2.2);
die 3-Wert-Analyse fügt auch den Nachbarn auf der Innenseite hinzu,
und der Lehrplan zeigt, was das bringt:
eine Prüfung als x ≤ 10 gedacht, aber als x = 10 geschrieben, besteht sowohl bei 10 als auch bei 11,
und nur 9 fängt es.
Die wiederkehrenden Ränder: leer, genau eins, viele; null und negativ;
das deklarierte Maximum und eins darüber;
der Wert, der genau der Puffer, das Limit, die Zeitüberschreitung ist.
Ein konkretes Paar von dieser Maschine: eine PATH-Prüfung, die bei 8.190 Zeichen in Ordnung ist und bei 8.192 fehlschlagen muss, muss bei diesen beiden Werten getestet werden. Ein Bestehen bei 4.000 und 12.000 sagt fast nichts über die Grenze dazwischen aus.
Wo die Grenze eine formulierte Vorbedingung ist,
ist der Wert darüber ein Fehler des Aufrufers und kein Fall mit einem erwarteten Ergebnis;
design-by-contract entscheidet, welche der beiden eine bestimmte Kante ist,
und der Test behauptet dann die zutreffende.
Die Seite, die die Spezifikation nicht nannte
„Bis zu 10 MB“ nennt ein Ende eines Bereichs. Das andere Ende existiert, ob der Satz es erwähnt oder nicht, und die aus dem Text abgeleiteten Fälle hören dort auf, wo der Text aufhört: eine Suite mit der Obergrenze getestet bei −1, 0 und +1 Bytes und nichts unter 1.024 hat eine Grenzwertanalyse auf einer Hälfte des Bereichs durchgeführt. Die Definition hat keine Seite: „die minimalen und maximalen Werte einer Partition sind ihre Grenzwerte“ (CTFL v4.0.1 §4.2.2). Schreiben Sie beide für jede Partition zuerst auf, dann nehmen Sie jeden mit seinem nächsten Nachbarn in der benachbarten Partition. Die unbenannte Seite ist normalerweise null, leer oder eins, und die Spezifikation schweigt normalerweise dazu, weil niemand entschieden hat.
Zwei Bedingungen gleichzeitig bewegen
Eine Suite, die durch Ändern einer Bedingung vom Happy Path aufgebaut wird, deckt jeden Wert jeder Bedingung und fast keine ihrer Kombinationen ab: Format falsch, Größe über, Anzahl über, jede allein, und kein Fall, bei dem zwei zusammen fehlschlagen. Welcher Fehler gewinnt, wenn beide zutreffen, steht selten in der Spezifikation, also verbirgt der fehlende Fall eine fehlende Entscheidung.
Legen Sie die Bedingungen als Entscheidungstabelle aus und zählen Sie die Regeln,
dann decken Sie die Regeln ab, bei denen zwei Bedingungen gleichzeitig fehlschlagen, und die Regel, bei der eine Rollenbeschränkung und eine Formateinschränkung beide zutreffen.
Beim Testen mit Entscheidungstabellen sind die Abdeckungselemente die Spalten mit realisierbaren Kombinationen,
und 100 % bedeutet jede solche Spalte getestet (CTFL v4.0.1 §4.2.3);
der Lehrplan fügt hinzu, dass die Tabelle „hilft, Lücken oder Widersprüche in den Anforderungen zu finden“,
was die oben genannte fehlende Entscheidung ist, die von selbst auftaucht.
Dasselbe Dokument kann als vollständig abgedeckt unter Each Choice und zu einem Viertel abgedeckt unter den Spalten gelesen werden,
und nur die zweite Zahl sagt etwas über die Kombinationen aus.
Wenn die Regelzahl das Produkt einer Menge von Flags ist,
ist die günstigere Lösung upstream:
state-first fasst die Flags in die Zustände zusammen, die auftreten können,
und die Tabelle schrumpft auf diese.
Eine Tabelle ist eine Behauptung über die Suite
Eine Zustandstabelle, eine Entscheidungstabelle, die Ablaufliste eines Anwendungsfalls: jede Zeile behauptet, dass ein Test für sie existiert. Setzen Sie die Test-ID in die Zeile. Eine Zeile ohne ID ist eine nicht abgedeckte Klasse, und die Zeile, die „nicht erlaubt“ lautet, ist diejenige, die am wahrscheinlichsten leer ist, weil das Schreiben des Verbots sich wie eine Behandlung anfühlte. Der verbotene Übergang — das zweite Senden, während eines in Bearbeitung ist — ist der Test, und die Wächterfunktion, die ihn stoppen soll, ist das zu testende Objekt.
Die Zustandstabelle macht diese Zeile explizit: ein ungültiger Übergang ist eine leere Zelle, und das stärkste der drei Kriterien, die der Lehrplan definiert, alle Übergänge abgedeckt, erfordert das Ausführen jedes einzelnen — ein Test pro Testfall, so dass ein Defekt keinen anderen maskieren kann (CTFL v4.0.1 §4.2.4). Abdeckung gültiger Übergänge, der 0-Wechsel, bei dem die meisten Suiten aufhören, berührt diese Zellen nie, weshalb eine ungetestete „nicht erlaubt“-Zeile grün bleibt.
Lesen Sie dann die beiden Dokumente gegeneinander. Ein Test, dessen Pfad nicht mit der Tabelle übereinstimmt (die Tabelle sagt fehlgeschlagen → sendet, der Test geht fehlgeschlagen → ausgewählt → sendet), bedeutet, dass eines von beiden falsch ist, und nichts außer dem Vergleich findet heraus, welches. Selbstübergänge und die Übergänge aus dem Fehlerzustand zählen ebenfalls als Zeilen.
Ein Ergebnis pro Fall
„Abgelehnt, oder falls akzeptiert, keine beschädigten Daten nach dem Senden“ kann nicht bestanden oder fehlschlagen. Es erscheint ehrlich, wenn die Spezifikation nie gesagt hat, was mit einer Datei von null Bytes passiert und der Autor es abgelehnt hat, sich eine Antwort auszudenken, und es überlebt die Überprüfung, weil der Fall sichtbar vorhanden ist. Die Disjunktion versteckt sich in der erwarteten Spalte. Die korrekte Form ist eine Frage an den Eigentümer der Spezifikation, als solche aufgeführt, und kein Test für diese Klasse, bis sie beantwortet ist.
Fehlerpfade sind auch Klassen
Die unglücklichen Pfade sind die, wo sich ungetesteter Code ansammelt, weil nichts sie im normalen Gebrauch ausübt — ein Sperreninhaber, der mitten im Lauf stirbt, ein zugeordneter Ordner, der nicht existiert, Eingabe mit dem erwarteten fehlenden Feld. Jedes ist eine Äquivalenzklasse mit dem gleichen Anspruch auf einen Test wie jeder Eingabebereich. Eine Suite, die nur beweist, dass das Werkzeug funktioniert, wenn alles kooperiert, hat die Demo getestet, nicht das Werkzeug.
Anwendungsfälle zählen die Klassen vor dem Code auf
Ein Anwendungsfall ist eine bereits in Klassen geschnittene Spezifikation: ein Hauptablauf, jeder alternative Ablauf, jeder Ausnahmeablauf, und die Vorbedingung, unter der jeder betreten werden kann. Wer ihn schrieb, hat die Aufzählung durchgeführt, die dieses Skill verlangt — die alternativen und Ausnahmeabläufe sind die Fehlerpfade — also hat eine Suite, die den Hauptablauf ausübt, eine Klasse von den N abgedeckt, die das Dokument auflistet.
Lesen Sie die Abläufe aus dem Anwendungsfall ab und geben Sie jedem seinen Test, dann überprüfen Sie die Vorbedingungen, denn ein Ablauf ist nur dann erreichbar, wenn seine Vorbedingung gelten kann. Ein Paritätscheck für übersetzte Seiten hat einen Hauptablauf (beide Sprachen bearbeitet und übertragen), einen alternativen Ablauf (eine einseitige Bearbeitung als Ausnahme deklariert), und zwei Ausnahmeabläufe, die erst auftauchen, wenn die Vorbedingungen aufgeschrieben sind: der Baum ist schmutzig, also kann die Veralterung noch nicht beurteilt werden; die Historie wurde umgeschrieben, also ist ein deklarierter Commit nicht mehr auflösbar. Beide traten innerhalb einer Woche auf einer Site auf. Der Happy Path allein hätte keinen von beiden gezeigt.
Ob ein Ausnahmeablauf tatsächlich auftreten kann, wird nicht dadurch entschieden, wie unwahrscheinlich er sich anfühlt.
Das Betriebsfenster sagt, was außerhalb des Rahmens liegt, und die Gefahrenanalyse sagt, was bleibt;
beide leben in assurance-case,
und dieses Skill akzeptiert die Liste, die sie produzieren, anstatt sie nach Intuition zu beschneiden.
Abdeckung ist eine Zahl unter einem benannten Kriterium
Ein Testdokument drei Wege gemessen: 100 % der Bedingungen, 90,9 % MC/DC,
25 % der Entscheidungsregeln.
Alle drei sind vom selben Datensatz wahr,
also sagt eine Abdeckungszahl ohne ihr Kriterium nichts,
und eine Zahl, deren Kriterium nach der Zählung gewählt wird, sagt noch weniger.
Nennen Sie es vor dem Zählen,
in den eigenen Begriffen des Lehrplans, damit die Zahl überprüft werden kann:
Partitionsabdeckung und Each Choice (§4.2.1),
2-Wert- oder 3-Wert-Grenzwertanalyse (§4.2.2), Entscheidungstabellen-Spalten (§4.2.3),
Alle Zustände, Gültige Übergänge oder Alle Übergänge (§4.2.4).
MC/DC ist nicht im Grundlagenlehrplan;
es stammt aus den Sicherheitsstandards (DO-178C, ISO 26262),
und es neben den anderen aufzuführen, ohne das zu sagen, ist die Art von gemischter Zitierung, die als Strenge gelesen wird.
Der Rest dessen, was eine Zahl ihrem Leser schuldet, steht in measured-claims.
Eine Suite überprüfen: zählen, nicht urteilen
Die Frage, ob eine Suite angemessen ist, gibt die blinden Flecken zurück, die sie produziert hat.
Eine zweite Sitzung mit demselben Modell teilt sie,
und dasselbe eine Person einen Tag später.
Der Lehrplan nennt das „etwas Unabhängigkeit“,
die zweite seiner vier Stufen, und sagt, wo der Wert herkommt:
„Unterschiede zwischen den kognitiven Verzerrungen des Autors und des Testers“ (CTFL v4.0.1 §1.5.3).
Eine zweite Sitzung mit demselben Modell teilt die Verzerrungen und behält nur das Etikett.
Der Schritt, der sie nicht teilt, ist das Zählen:
Listen Sie die Klassen aus der Spezifikation auf und haken Sie die mit einem Test ab,
listen Sie beide Grenzen jedes Bereichs auf, listen Sie die Regeln der Entscheidungstabelle auf,
listen Sie die Zeilen jeder Zustandstabelle auf,
und zitieren Sie die Datei und die Zeile jeder Lücke.
Ob ein erwarteter Wert richtig ist, bleibt ein Urteil und bleibt bei einem Leser, der ihn nicht geschrieben hat;
ob eine Klasse einen Test hat, ist Arithmetik.
Wenn die Zählung eine Stichprobe und nicht erschöpfend war,
sagt der Bericht "Stichprobe".
Die Form der Widerlegung durch Voreinstellung für das Urteil steht in adversarial-verify;
dieses Skill liefert, was zu zählen ist.
Wenn die Anfrage eine Klasse entfernt
„Das doppelte Senden kann nicht passieren, weil der Button deaktiviert ist, streichen Sie diese Zeile“ entfernt eine Klasse aus der Suite mit der Stärke einer Wächterfunktion in einer Schicht. Tun Sie, was gefragt wurde, und sagen Sie in einem Satz, welche Klasse jetzt ungedeckt ist und was sie erreichen würde: die Zustandsmaschine akzeptiert immer noch ein zweites Senden von jedem Aufrufer, der nicht der Button ist. Eine mit diesem Satz gelöschte Zeile ist eine Entscheidung; eine ohne diesen Satz gelöschte Zeile ist eine Lücke, die niemand wiederfinden wird.
Ein unimplementierter Pfad hat einen Test, der das sagt
Ein absichtlich aus dieser Änderung ausgelassener Pfad,
eine Rolle, die diese Version nicht unterstützt, ein noch nicht verarbeitetes Format,
ein Branch, der NotImplementedException wirft oder todo!() aufruft,
ist immer noch eine Klasse der Eingabe,
und die Suite zeichnet auf, was dort heute passiert.
Schreiben Sie den Test, dass der Pfad als unimplementiert zurückgewiesen wird:
die Ausnahme oder den Fehlerwert, den er auslöst,
das fehlende Menüelement, die Antwort, die „nicht unterstützt“ lautet.
Dieser Test besteht jetzt und erledigt zwei Aufgaben. Er setzt die Lücke in die Liste der Suite, wo ein Leser, der Klassen zählt, sie findet, anstatt in einem Kommentar oder einem Ticket. Und er wird rot an dem Tag, an dem jemand den Pfad implementiert, was der Moment ist, in dem seine echten Fälle geschrieben werden müssen; der fehlschlagende Test ist die Erinnerung, und er wird ersetzt, nicht gelöscht.
Ein Überspring-Marker oder ein ausstehender Test ist kein solcher Test. Ein ausstehender Test ist eine Leerstelle, die nicht rot werden kann; der Ersatz für ihn ist der echte Test, sobald er geschrieben ist.