Ihre Arbeitsmittel

Automatisierte Tests sind im Grunde nur Code, der einen Fehler auslöst, wenn dass etwas nicht stimmt. Die meisten Bibliotheken oder Test-Frameworks bieten eine Vielzahl von Primitiven, die das Schreiben von Tests erleichtern.

Wie im vorherigen Abschnitt erwähnt, enthalten diese Primitive fast immer ein Möglichkeit, unabhängige Tests (auch Testfälle genannt) zu definieren und Assertions an. Mit Assertions können Sie die Prüfung eines Ergebnisses wenn etwas nicht in Ordnung ist, und kann als Grundprimitiv aller Primitive testen.

Auf dieser Seite wird ein allgemeiner Ansatz für diese Primitive erläutert. Ihr ausgewähltes Framework wahrscheinlich so etwas, aber das ist keine genaue Referenz.

Beispiel:

import { fibonacci, catalan } from '../src/math.js';
import { assert, test, suite } from 'a-made-up-testing-library';

suite('math tests', () => {
  test('fibonacci function', () => {
    // check expected fibonacci numbers against our known actual values
    // with an explanation if the values don't match
    assert.equal(fibonacci(0), 0, 'Invalid 0th fibonacci result');
    assert.equal(fibonacci(13), 233, 'Invalid 13th fibonacci result');
  });
  test('relationship between sequences', () => {
    // catalan numbers are greater than fibonacci numbers (but not equal)
    assert.isAbove(catalan(4), fibonacci(4));
  });
  test('bugfix: check bug #4141', () => {
    assert.isFinite(fibonacci(0)); // fibonacci(0) was returning NaN
  })
});

In diesem Beispiel wird eine Gruppe von Tests (manchmal auch als Suite bezeichnet) namens „Mathematik“ erstellt Tests“ und definiert drei unabhängige Testfälle, in denen jeweils einige Assertions ausgeführt werden. Diese Testläufe können in der Regel individuell angegangen oder durchgeführt werden, beispielsweise von einem Filter-Flag in Ihrem Test-Runner.

Assertion Helper als Primitive

Die meisten Test-Frameworks, einschließlich Vitest, enthalten eine Sammlung von Assertions für ein assert-Objekt verwenden, mit denen Sie schnell Rückgabewerte oder anderen Bundesstaaten gegen eine Erwartung verstoßen. Diese Erwartung ist oft „als gut bekannt“ Werte. Im vorherigen Beispiel wissen wir, dass die 13. Fibonacci-Zahl 233, damit wir dies direkt mit assert.equal bestätigen können.

Vielleicht haben Sie auch die Erwartung, dass ein Wert eine bestimmte Form oder größer als ein anderer Wert oder eine andere Eigenschaft haben. In diesem Kurs werden decken alle möglichen Assertion-Hilfsmittel ab, aber testen Sie Frameworks. sollten Sie immer mindestens die folgenden grundlegenden Prüfungen bereitstellen:

  • Eine „Wahrheit“ wird oft als „ok“ bezeichnet ob eine Bedingung erfüllt ist, wie Sie eine if schreiben, die prüft, ob etwas erfolgreich ist, richtig. Dies wird in der Regel als assert(...) oder assert.ok(...) angegeben. enthält einen einzelnen Wert und einen optionalen Kommentar.

  • Eine Gleichheitsprüfung, wie im mathematischen Testbeispiel, bei dem gibt den Wert oder Zustand eines Objekts zurück, der einem als funktionierend bekannten Wert entspricht. Diese sind für primitive Gleichheit (z. B. für Zahlen und Strings) oder referenzielle Gleichheit (sind dies dasselbe Objekt). Im Grunde sind dies nur eine „Wahrheit“ Häkchen setzen mit einem ==- oder ===-Vergleich.

    • JavaScript unterscheidet zwischen lose (==) und strenger (===) Gleichheit. Die meisten Testbibliotheken bieten Ihnen die Methoden assert.equal und assert.strictEqual.
  • Umfangreiche Gleichheitsprüfungen, die auch die Prüfung der Inhalte von Objekten, Arrays und anderen komplexeren Datentypen intern Logik, um Objekte zu durchsuchen und sie zu vergleichen. Diese sind wichtig, da es in JavaScript keine Möglichkeit gibt, zwei Objekten oder Arrays. Beispiel: [1,2,3] == [1,2,3] ist immer „false“. Testen Frameworks umfassen häufig deepEqual- oder deepStrictEqual-Hilfsmittel.

Assertion Helper, die zwei Werte vergleichen (anstatt nur eine Wahrheitsprüfung durchzuführen) mit zwei oder drei Argumenten:

  • Der tatsächliche Wert, wie durch den zu testenden Code generiert oder der den zu überprüfen.
  • den erwarteten Wert, in der Regel hartcodiert (z. B. eine Literalzahl oder String).
  • Ein optionaler Kommentar, der beschreibt, was erwartet wurde oder was fehlgeschlagen sein könnte, die bei Ausfall dieser Zeile eingefügt wird.

Es ist auch üblich, Assertions zu kombinieren, um eine Vielzahl von da der Status Ihrer Website in seltenen Fällen für sich genommen hat. Beispiel:

  test('JWT parse', () => {
    const json = decodeJwt('eyJieSI6InNhbXRob3Ii');

    assert.ok(json.payload.admin, 'user should be admin');
    assert.deepEqual(json.payload.groups, ['role:Admin', 'role:Submitter']);
    assert.equal(json.header.alg, 'RS265')
    assert.isAbove(json.payload.exp, +new Date(), 'expiry must be in future')
  });

Vitest verwendet die Chai-Assertion-Bibliothek um intern ihre Assertion Helper zur Verfügung zu stellen. Es kann nützlich sein, um zu sehen, welche Assertions und Hilfsmethoden für Ihren Code geeignet sind.

Fließende und BDD-Assertions

Einige Entwickler bevorzugen einen Assertion-Stil, der als verhaltensgesteuert bezeichnet werden kann. Entwicklung oder Fließend Assertions an. Diese werden auch als „erwarten“ bezeichnet. Helfer:innen, da der Einstiegspunkt für zur Überprüfung der Erwartungen ist eine Methode mit dem Namen expect().

Erwarten, dass Hilfskräfte sich genauso verhalten wie Assertions, die als einfache Methode geschrieben wurden Anrufe wie assert.ok oder assert.strictDeepEquals, aber einige Entwickler finden diese leichter zu lesen. Eine BDD-Assertion könnte so aussehen:

// A failure here would generate "Expect result to be an array that does include 42"
const result = await possibleMeaningsOfLife();
expect(result).to.be.an('array').that.does.include(42);

// or a simpler form
expect(result).toBe('array').toContainEqual(42);

// the same in assert might be
assert.typeOf(result, 'array', 'Expected the result to be an array');
assert.include(result, 42, 'Expected the result to include 42');

Diese Art von Assertions funktionieren aufgrund der Methodenverkettung, wobei das von expect zurückgegebene Objekt kontinuierlich mit für weitere Methodenaufrufe. Einige Teile des Anrufs, darunter to.be und that.does im vorherigen Beispiel, haben keine Funktion und werden nur einbezogen, um den Aufruf durchzuführen. einfacher zu lesen und möglicherweise einen automatisierten Kommentar zu generieren, wenn der Test fehlgeschlagen. Hinweis: expect unterstützt normalerweise keine optionalen Kommentare, weil sollte der Fehler in der Verkettung klar beschrieben werden.)

Viele Test-Frameworks unterstützen sowohl Fluent/BDD als auch normale Assertions. Vitest Exportiert beispielsweise beide Chai hat einen etwas präziseren Ansatz für BDD. Schatz, enthält dagegen nur ein erwarten Methode standardmäßig.

Tests dateiübergreifend gruppieren

Beim Schreiben von Tests neigen wir bereits dazu, implizite Gruppierungen bereitzustellen, anstatt als alle Tests in einer Datei sind, schreiben Sie sie häufig für mehrere Dateien. Tatsächlich wissen Test-Runner normalerweise nur, dass eine Datei zu Testzwecken dient, eines vordefinierten Filters oder regulären Ausdrucks – Vitest beispielsweise enthält alle Dateien in Ihrem Projekt, die mit einer Endung wie „.test.jsx“ enden oder „.spec.ts“ („.test“ und „.spec“ plus eine Reihe gültiger Erweiterungen).

Komponententests befinden sich in der Regel in einer Peer-Datei mit der zu testenden Komponente. wie in der folgenden Verzeichnisstruktur:

<ph type="x-smartling-placeholder">
</ph> Eine Liste der Dateien in einem
  -Verzeichnis, einschließlich UserList.tsx und UserList.test.tsx.
Eine Komponentendatei und die zugehörige Testdatei.

Ebenso werden Einheitentests tendenziell neben dem zu testenden Code platziert. End-to-End-Tests können sich jeweils in einer eigenen Datei befinden, und Integrationstests können sogar eigenen Ordnern zugeordnet werden. Diese Strukturen können hilfreich sein, Bei komplexen Testläufen werden immer mehr eigene Dateien benötigt, die keine Test-Supportdateien sind, z. B. Supportbibliotheken, die nur für einen Test benötigt werden.

Tests innerhalb von Dateien gruppieren

Wie in vorherigen Beispielen verwendet, werden Tests üblicherweise innerhalb eines Aufrufs von suite() gruppiert, die Tests gruppiert, die Sie mit test() eingerichtet haben. Suiten sind normalerweise nicht Tests selbst testen, helfen aber, Struktur zu schaffen, indem sie verwandte Tests gruppieren durch Aufrufen der übergebenen Methode. Für test() beschreibt die übergebene Methode die Aktionen des Tests selbst.

Wie bei Behauptungen gibt es in Fluent/BDD eine ziemlich Standard-Äquivalenz Gruppierungstests. Im folgenden Code werden einige typische Beispiele verglichen:

// traditional/TDD
suite('math tests', () => {
  test('handle zero values', () => {
    assert.equal(fibonacci(0), 0);
  });
});

// Fluent/BDD
describe('math tests', () => {
  it('should handle zero values', () => {
    expect(fibonacci(0)).toBe(0);
  });
})

In den meisten Frameworks verhalten sich suite und describe ähnlich, genau wie test und it im Gegensatz zu den größeren Unterschieden zwischen expect und assert Assertions zu erstellen.

Andere Tools haben sehr unterschiedliche Ansätze zur Anordnung von Suiten und Tests. Für Der integrierte Test-Runner von Node.js unterstützt das Verschachteln von Aufrufen von test() zur implizit eine Testhierarchie zu erstellen. Vitest lässt jedoch nur diese Art von Verschachtelung mit suite() und führt keine test() aus, die in einem anderen test() definiert ist.

Denken Sie wie bei Assertions daran, dass die genaue Kombination Methoden, die Ihr Technology Stack bietet, ist nicht so wichtig. In diesem Kurs geht es um aber Sie müssen herausfinden, wie sie sich auf Ihre die Wahl der Tools.

Lebenszyklusmethoden

Ein Grund dafür, Tests zu gruppieren, auch implizit auf der obersten Ebene innerhalb eines ist die Bereitstellung von Einrichtungs- und Teardown-Methoden, die für jeden Test ausgeführt werden. für eine Gruppe von Tests. Die meisten Frameworks bieten vier Methoden:

Für jeden `test()` oder `it()` Einmal für die Suite
Vor den Testläufen „beforeEvery()“ `beforeAll()`
Nach den Testläufen „afterEvery()“ „afterAll()“

Sie können beispielsweise eine virtuelle Nutzerdatenbank vor jeder Datenbank und anschließend löschen:

suite('user test', () => {
  beforeEach(() => {
    insertFakeUser('bob@example.com', 'hunter2');
  });
  afterEach(() => {
    clearAllUsers();
  });

  test('bob can login', async () => {  });
  test('alice can message bob', async () => {  });
});

Dies kann nützlich sein, um Ihre Tests zu vereinfachen. Sie können gemeinsame Einrichtungs- und den Code zu löschen, anstatt ihn bei jedem Test zu duplizieren. Wenn der Parameter beim Einrichtungs- und Teardown-Code selbst einen Fehler aus, der auf strukturelles bei denen die Tests nicht fehlschlagen.

Allgemeine Empfehlungen

Hier sind ein paar Tipps, die du im Zusammenhang mit diesen Primitiven beachten solltest.

Primitiven dienen als Leitfaden

Denken Sie daran, dass die Tools und Primitive hier und auf den nächsten Seiten genau Vitest, Jest, Mocha, Web Test Runner oder einem anderen spezifisches Framework. Obwohl wir Vitest als allgemeiner Leitfaden verwendet haben, achten Sie darauf, das Framework Ihrer Wahl.

Assertions nach Bedarf kombinieren

Tests sind im Grunde Code, der Fehler auslösen kann. Jeder Läufer gibt Primitiv, wahrscheinlich test(), zur Beschreibung unterschiedlicher Testfälle.

Wenn dieser Runner jedoch auch assert(), expect() und Assertion-Assistenten bereitstellt, Denken Sie daran, dass es hier mehr um Komfort geht. Sie können ihn überspringen, die Sie brauchen. Sie können beliebigen Code ausführen, der zu einem Fehler führen könnte, einschließlich anderer Assertion-Bibliotheken oder eine altmodische if-Anweisung verwenden.

IDE-Einrichtung kann lebensretten

Dafür sorgen, dass Ihre IDE, z. B. VSCode, Zugriff auf die automatische Vervollständigung und die Dokumentation zu den gewählten Testtools, können Sie produktiver sein. Für Beispiel: Es gibt über 100 Methoden für assert in der Chai-Assertion und eine Dokumentation für die rechten Inline erscheinen, wäre das praktisch.

Dies kann besonders wichtig für einige Test-Frameworks sein, die globalen Namespace mit seinen Testmethoden. Das ist ein kleiner Unterschied, ist es oft möglich, Testbibliotheken zu verwenden, ohne sie zu importieren, wenn sie automatisch zum globalen Namespace hinzugefügt:

// some.test.js
test('using test as a global', () => {  });

Wir empfehlen, die Hilfsfunktionen zu importieren, auch wenn sie automatisch unterstützt werden. denn das gibt Ihrer IDE eine klare Möglichkeit, diese Methoden nachzuschlagen. (Möglicherweise haben Sie ist beim Erstellen von React dieses Problem aufgetreten, da einige Codebasen eine magische React ist global, bei anderen jedoch nicht. Daher muss der Import in alle Dateien mit React.)

// some.test.js
import { test } from 'vitest';
test('using test as an import', () => {  });