Was, wenn Tests sich selbst schreiben? Einführung in Property-based Testing
\n\nHaben Sie jemals einen Unit-Test geschrieben, ihn ausgeführt, einen grünen Haken bekommen und einen Monat später einen Bug in derselben Funktion gefunden? Kommt Ihnen bekannt vor? Klassische Unit-Tests sind wie zu prüfen, ob Ihr Geldbeutel nicht leer ist, indem Sie nur auf einen einzigen Schein schauen. Sie überprüfen ein einziges konkretes Szenario, einen einzigen Satz von Eingabedaten. Was wäre, wenn ich Ihnen sage, dass es eine Möglichkeit gibt, den Computer dazu zu bringen, selbst Tausende verschiedener Szenarien zu erfinden und zu prüfen, ob Ihr Code nicht kaputt geht?
\n\nDas ist keine Science-Fiction. Das ist Property-basiertes Testen in JavaScript (oder eigenschaftsbasiertes Testen). Anstatt zu schreiben „wenn man 2 und 3 übergibt, erhält man 5“, beschreiben Sie eine Eigenschaft (Property) Ihrer Funktion: „Für zwei beliebige Zahlen ist das Ergebnis der Addition eine Zahl, die immer größer oder gleich jeder der Summanden ist.“ Und die Testumgebung generiert hunderte zufällige Zahlenpaare und überprüft diese Behauptung.
\n\nIn diesem Artikel werden wir uns ansehen, wie Property-basiertes Testen funktioniert, wie es sich von gewöhnlichen Tests unterscheidet und wie Sie es mit der großartigen Bibliothek fast-check in Ihr Projekt integrieren können. Sie werden sehen, wie einfach es ist, „grenzwertige“ Bugs zu finden, nach denen Sie nicht einmal zu suchen gedacht hätten.
Warum gewöhnliche Unit-Tests nicht immer retten?
\n\nKommen wir gleich zur Sache. Angenommen, Sie haben eine Funktion, die ein Zahlen-Array aufsteigend sortiert:
\n\nfunction sortNumbers(arr) {\n return arr.slice().sort((a, b) => a - b);\n}\n\nSie schreiben einen Unit-Test:
\n\ntest('sortiert das Array [3, 1, 2]', () => {\n expect(sortNumbers([3, 1, 2])).toEqual([1, 2, 3]);\n});\n\nDer Test ist grün. Sie sind glücklich. Aber was, wenn das Array null enthält? Oder undefined? Oder sehr große Zahlen? Oder ein Array mit 10.000 Elementen? Sie werden nicht für jeden dieser Fälle einen Test schreiben. Aber Property-basiertes Testen in JavaScript wird es tun.
Anstatt Beispiele aufzuzählen, beschreiben Sie Invarianten (Eigenschaften), die immer wahr sein müssen:
\n- \n
- Die Länge des sortierten Arrays ist gleich der Länge des ursprünglichen Arrays. \n
- Jedes Element des ursprünglichen Arrays ist im sortierten Array vorhanden. \n
- Für jeden Index
igilt, dassarr[i] <= arr[i+1]. \n
Genau diese Eigenschaften wird das Testen von Eigenschaften überprüfen.
\n\nDie Bibliothek fast-check: Ihr Helfer beim Zufallstesten
\n\nIn der Welt von JavaScript ist das wichtigste Werkzeug für Property-based Testing fast-check. Es kann zufällige Daten aller Art generieren: Zahlen, Zeichenketten, Arrays, Objekte, Daten – und sogar komplexe Strukturen.
\n\nDie Installation ist einfach:
\nnpm install fast-check --save-dev\n\nJetzt schreiben wir unseren ersten Property-based Test für die Funktion sortNumbers. Wir verwenden das Framework Jest, aber fast-check funktioniert mit jedem Test-Runner.
const fc = require('fast-check');\n\ntest('Sortieren erhält die Array-Länge', () => {\n fc.assert(\n fc.property(fc.array(fc.integer()), (arr) => {\n const sorted = sortNumbers(arr);\n return sorted.length === arr.length;\n })\n );\n});\n\nWas passiert hier? fc.array(fc.integer()) ist ein Generator, der zufällige Arrays mit zufälligen ganzen Zahlen erstellt. fc.property nimmt diesen Generator und überprüft die Behauptung (unsere Pfeilfunktion) mit 100 (standardmäßig) verschiedenen Datensätzen. Wenn auch nur ein Test fehlschlägt, wirft fc.assert einen Fehler und zeigt ein Gegenbeispiel an.
Weitere Eigenschaften hinzufügen
\n\nEine Eigenschaft ist gut, aber drei sind besser. Lassen Sie uns überprüfen, ob das Array nach dem Sortieren tatsächlich geordnet ist:
\n\ntest('Sortieren gibt ein geordnetes Array zurück', () =>