Reine Funktionen sind der perfekte Fall für Unit-Tests. Für eine gegebene Eingabe erwarten wir immer die gleiche Ausgabe – es ist kein interner Zustand beteiligt. Schauen wir uns ein paar Beispiele und einige einfache Tests an, die prüfen, ob die Methoden wie erwartet funktionieren.
Jasmine ist ein Unit-Test-Framework für JavaScript. Es kann Tests sowohl in Node.js als auch im Browser ausführen. Es wird im Angular-Framework verwendet und ist besonders in Projekten beliebt, die auf Angular basieren. Es ist eine gute Wahl für Vanilla JS-Projekte oder auch Projekte, die auf anderen Frameworks basieren.
Beim Happy-Path-Testen testen wir eine Methode mit Eingaben, von denen erwartet wird, dass sie normal funktioniert. Die Argumente sind gültig und liegen in angemessenen Grenzen. Bei diesen Tests wird überprüft, ob die Methode ihre Aufgabe korrekt erfüllt. Die Testfälle sollten einfache Beispiele dafür sein, wie die Methode in ihrer Dokumentation erklärt wird.
Pseudocode-Beispiele:
expect(add(2, 2)).toBe(4)
,
expect(concatenate(“Lorem”, “Ipsum”)).toBe(“LoremIpsum”)
Diese Tests sollen es automatisch abfangen, wenn das Verhalten des Methodenschlüssels fehlerhaft ist.
Sehen wir uns ein paar einfache Methoden an: einfache Operationen, die wir möglicherweise in einigen realen Anwendungen benötigen.
Alle Implementierungen sind stark vereinfacht – alle Methoden werden auf hässliche Weise kaputt gehen, wenn wir ihnen nur Parameter zur Verfügung stellen, die geringfügig von den Erwartungen abweichen. Der Code ist alles andere als robust.
Methode, die den Benutzer mit seinem Vor- und Nachnamen begrüßt:
export function greet(name, surname) { return `Hello ${name} ${surname}!`; }
shortDate
ist eine Formatierungsmethode, die ein Datumsobjekt nimmt und es formatiert als kurze Zeichenfolge zurückgibt. Der Code:
export function shortDate(date) { return date.toISOString().substring(0, 10); }
ellipsis
nimmt eine lange Textzeichenfolge und einen optionalen Längenparameter und schneidet die Zeichenfolge dann so zu, dass sie in den Grenzwert passt:
export function ellipsis(text, length = 50) { if (text.length > length) { return text.substring(0, length) + "…"; } return text; }
Eine Methode, die übersetzte Zeichenfolgenwerte für ein key
und lang
-Paar bereitstellt. Es handelt sich um eine vereinfachte Implementierung dessen, was durch fortschrittlichere Übersetzungsbibliotheken ersetzt werden könnte.
export function translate(key, lang = "en") { switch (lang) { case "en": switch (key) { case "hello": return "Hello!"; } case "pl": switch (key) { case "hello": return "Cześć!"; } } }
Methode zum Anwenden eines prozentualen Rabatts auf einen Preis. Mit dieser naiven Implementierung kann es sich übertrieben anfühlen, aber später, wenn wir anfangen, Randfälle zu untersuchen, wird es viel interessanter.
export function applyDiscount(price, discountPercentage) { return price - (price * discountPercentage) / 100; }
Dieser berechnet den Gesamtpreis beim Kauf mehrerer Einheiten zu einem bestimmten Preis. Es wird auch komplizierter, wenn interessante Randfälle hinzugefügt werden.
export function calculatePrice(unitPrice, quantity) { return unitPrice * quantity; }
Der vollständige JS-Code, src/main.js
:
export function greet(name, surname) { return `Hello ${name} ${surname}!`; } export function shortDate(date) { return date.toISOString().substring(0, 10); } export function ellipsis(text, length = 50) { if (text.length > length) { return text.substring(0, length) + "…"; } return text; } export function translate(key, lang = "en") { switch (lang) { case "en": switch (key) { case "hello": return "Hello!"; } case "pl": switch (key) { case "hello": return "Cześć!"; } } } export function applyDiscount(price, discountPercentage) { return price - (price * discountPercentage) / 100; } export function calculatePrice(unitPrice, quantity) { return unitPrice * quantity; }
Um Jasmine hinzuzufügen, beginnen wir mit der Konvertierung des Ordners in ein npm-Paket:
$ npm init -y Wrote to …/package.json: …
Dann können wir das Jasmine-Paket installieren:
$ npm install --save-dev jasmine added 42 packages, and audited 43 packages in 2s 13 packages are looking for funding run `npm fund` for details found 0 vulnerabilities
Dann können wir von Jasmine verwendete Ordner und Dateien generieren:
$ npx jasmine init (no output)
Dieser Befehl generiert Folgendes:
spec/
– ein Ordner, in dem wir *.spec.js
Dateien mit dem Test ablegen können, und
spec/support/jasmine.json
– eine Datei mit der Jasmine-Konfiguration.Bei den folgenden Komponententests konzentriere ich mich nur auf den glücklichen Weg – ich überprüfe, ob das Ergebnis für vernünftige Eingaben den Erwartungen entspricht. Der Test sollte selbsterklärend sein, also werfen wir einen Blick darauf:
import { greet, shortDate, ellipsis, translate, applyDiscount, calculatePrice, } from "../src/main.js"; describe("main", () => { describe("greet", () => { it("should greet by name and surname", () => { expect(greet("Lorem", "Ipsum")).toEqual("Hello Lorem Ipsum!"); }); }); describe("shortDate", () => { it("should format correclty date", () => { const date = new Date("2023-11-02"); expect(shortDate(date)).toEqual("2023-11-02"); }); }); describe("shortDate", () => { it("should shorten long text at 50 chars", () => { expect( ellipsis( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque a faucibus massa." ) ).toEqual("Lorem ipsum dolor sit amet, consectetur adipiscing…"); }); it("should leave short text unchanged", () => { expect(ellipsis("Lorem ipsum sin dolor")).toEqual( "Lorem ipsum sin dolor" ); }); it("should shorten to custom length", () => { expect(ellipsis("Lorem ipsum sin dolor", 10)).toEqual("Lorem ipsu…"); }); }); describe("translate", () => { it("should translate to supported langauges", () => { expect(translate("hello", "en")).toEqual("Hello!"); expect(translate("hello", "pl")).toEqual("Cześć!"); }); }); describe("applyDiscount", () => { it("should lower the price accordingly", () => { expect(applyDiscount(120, 25)).toEqual(90); expect(applyDiscount(8, 50)).toEqual(4); }); }); describe("calculatePrice", () => { it("should find a price of many products", () => { expect(calculatePrice(4, 3)).toEqual(12); expect(calculatePrice(9, 0.5)).toEqual(4.5); }); }); });
(Datei spec/main.spec.js
)
Um die Tests auszuführen, können wir das folgende Skript zu package.json
hinzufügen:
.. "scripts": { "test": "jasmine" }, …
Nachdem dies geschehen ist, führt npm run test
unsere Tests aus:
$ npm run test > [email protected] test > jasmine Randomized with seed 76873 Started ........ 8 specs, 0 failures Finished in 0.004 seconds Randomized with seed 76873 (jasmine --random=true --seed=76873)
In diesem Beitrag haben wir uns ein einfaches Beispiel für JS-Code angesehen und gezeigt, wie dieser durch Unit-Tests abgedeckt werden kann. Das vollständige Codebeispiel finden Sie auf GitHub .
Auch hier veröffentlicht