Blog.

Behauptungen in automatisierten Tests: Konsolidierung von Behauptungen
Unabhängig davon, welche Rolle Sie bei der Erstellung automatisierter Tests spielen (Unit, Integration, End-to-End usw.), sind wir uns alle einig, dass das Ziel eine vollständige Codeabdeckung ist, damit wir sicherstellen können, dass unsere Anwendungen immer wie erwartet funktionieren. Dazu gehört die Durchführung von Assertions für die Ergebnisse von API-Aufrufen, Werte und Zustände von Komponenten auf einer Benutzeroberfläche oder unzählige andere Szenarien. Das bedeutet, dass mehrere Werte in einem Test überprüft werden müssen. Eine gängige Praxis, um dies zu erreichen, ist das Schreiben einer einzelnen Behauptung für jeden Wert.
const result = await getVehicle({ id: 1 }); expect(result.make).toEqual('Chevy'); expect(result.model).toEqual('Colorado'); expect(result.year).toEqual(2022); expect(result.trim).toEqual('LT'); expect(result.color).toEqual('Summit White');
Diese Technik funktioniert zwar, aber wir haben ein Problem. Standardmäßig stoppen die meisten automatisierten Test-Frameworks die Ausführung bei einer fehlgeschlagenen Assertion und es werden keine weiteren Assertions ausgeführt. Um das obige Beispiel zu nehmen, wenn expect(result.make).toEqual('Chevy')
versagt, bleibt alles stehen.
Schlimmer noch, wir wüssten nicht, ob andere Behauptungen erfolgreich sind oder nicht, bis die erste Behauptung erfolgreich ist. Wenn andere fehlschlagen, würden wir den Prozess wieder von vorne beginnen.

Im Allgemeinen wird empfohlen, eine Behauptung in einem Test anzustreben. Das obige Beispiel könnte in mehrere Tests aufgeteilt werden, aber das wäre mit einem Test für jeden Eigenschaftswert übermäßig umfangreich. Ganz zu schweigen davon, dass dies weit von jeglichem Potenzial zur Wiederverwendung von Code entfernt wäre. Glücklicherweise gibt es Strategien zur Konsolidierung mehrerer Behauptungen, um ein vollständiges Bild aller Ergebnisse in einem einzigen Test zu erhalten.
Die folgenden Beispiele werden unter Verwendung von Jest als Testframework gezeigt, aber die meisten anderen Testframeworks sollten ähnliche Möglichkeiten bieten.
Objektübereinstimmungs-Assertions verwenden
Das obige Beispiel, aber jetzt mit einer Objektübereinstimmungs-Assertion:
const expected = { make: 'Chevy', model: 'Colorado', year: 2022, trim: 'LT', color: 'Summit White' } const result = await getVehicle({ id: 1 }); expect(result).toMatchObject(expected);
Durch die Verwendung des toMatchObject() Matcher erhalten Sie ein konsolidiertes Ergebnis, wenn mehrere Eigenschaftswerte unterschiedlich sind. Nachfolgend ein Beispiel für eine Ergebnisausgabe, wenn beide model
und trim
Werte nicht übereinstimmen.
expect(received).toMatchObject(expected) - Expected - 2 + Received + 2 Object { "color": "Summit White", "make": "Chevy", - "model": "Colorado", - "trim": "LT", + "model": "Silverado", + "trim": "LTD", "year": 2022, }
Mit diesem konsolidierten Ergebnis werden alle Fehler mit einem einzigen Testdurchlauf identifiziert! Diese einfache Änderung spart den Software- und Qualitätsingenieuren Zeit und verkürzt die CI/CD-Zyklen, wodurch die Software schneller bereitgestellt werden kann.

Jedes Testframework verfügt über mehrere Assertion/Matcher-Funktionen für Objekte, die ihre Assertion leicht unterschiedlich ausführen. Die Funktion `toMatchObject()` wurde hier ausgewählt, da sie ihre Behauptung auf eine Weise durchführt, die mehreren einzelnen Behauptungsanweisungen ähnelt. Es wird nur eine Teilmenge von Eigenschaften geprüft, indem nur das überprüft wird, was im "erwarteten" Objekt angegeben ist.
Einen benutzerdefinierten Matcher verwenden
Objekt-Matcher helfen definitiv bei der Konsolidierung von Assertions, wenn Sie nur Eigenschaftswerte überprüfen, aber was ist, wenn Sie eine Reihe von gemeinsamen Assertions haben, die mehr als nur Eigenschaftswerte überprüfen? Mit Jest können Sie Ihren eigenen benutzerdefinierten Abgleicher erstellen, indem Sie expect.extend() verwenden. Damit können Sie sehr robuste Assertions erstellen, die eine beliebige Anzahl anderer Assertions konsolidieren können, um eine effektive Wiederverwendung des Codes zu ermöglichen und letztlich die Lesbarkeit des Codes innerhalb der Tests zu verbessern.
Der folgende Code definiert unseren benutzerdefinierten Matcher.
expect.extend({ toMatchVehicle(vehicle, expected) { if (!vehicle instanceof Vehicle) { return { message: () => 'The expect() parameter must be an instance of Vehicle to perform toMatchVehicle() assertion.', pass: this.isNot }; } const failures = []; if(!this.equals(vehicle.make, expected.make)) { failures.push(`Expected vehicle make: "${expected.make}" - Actual: "${vehicle.make}"`); } if(!this.equals(vehicle.model, expected.model)) { failures.push(`Expected vehicle model: "${expected.model}" - Actual: "${vehicle.model}"`); } if(!this.equals(vehicle.year, expected.year)) { failures.push(`Expected vehicle year: "${expected.year}" - Actual: "${vehicle.year}"`); } const pass = failures.length === 0; if(pass) { return { message: () => 'Expected vehicle not to match, but it did.', pass: true }; } else { return { message: () => { let msg = `The vehicles did not match:n` failures.forEach((failure) => { msg += `- ${failure}n` }) return msg }, pass: false } } } });
Die Verwendung der benutzerdefinierten Matcher-Assertion.
const expected = new Vehicle({ make: 'Chevy', model: 'Colorado', year: 2022 }); const result = await getVehicle({ id: 1 }); expect(result).toMatchVehicle(expected);
Schließlich ein Beispiel für die Ausgabe bei Fehlern.
Die Fahrzeuge stimmten nicht überein: - Erwartete Fahrzeugmarke: "Chevy" - Tatsächliche: "Ford" - Erwartetes Fahrzeugjahr: "2022" - Tatsächliches Jahr: "2021"
Zugegeben, dieses Beispiel für einen benutzerdefinierten Abgleich ist sehr ausführlich und die Prüfungen sind recht einfach. Dennoch zeigt es einige der wichtigsten Vorteile der Erstellung eines benutzerdefinierten Abgleichs.
- Fähigkeit, mehrere Arten von Prüfungen innerhalb einer einzigen Behauptung durchzuführen
- Möglichkeit zur Anpassung der Fehlermeldungen, wenn eine Assertion fehlschlägt
Diese Vorteile führen letztendlich zu einem verbesserten Debugging mit weniger und kürzeren Code-Iterationszyklen.

Zusammenfassung
Wir haben den großen Nachteil der Verwendung von mehreren eng begrenzten Assertions untersucht. Anschließend haben wir gezeigt, dass Object Matcher und Custom Matcher Assertions hervorragende Alternativen sind. Wir hoffen, dass diese Techniken Ihnen helfen können, effektivere Tests zu erstellen und Ihre Testiterationen zu reduzieren. Viel Spaß beim Testen!
FloQast wächst und wir sind auf der Suche nach großartigen Software-Ingenieuren und SDETs. Schauen Sie sich unsere aktuellen offenen Stellen an!
Zurück zu Blog