Les fonctions pures constituent le cas idéal pour les tests unitaires. Pour une entrée donnée, nous attendons toujours le même résultat : aucun état interne n’est impliqué. Jetons un coup d'œil à quelques exemples et quelques tests simples qui vérifient si les méthodes fonctionnent comme prévu.
Jasmine est un framework de tests unitaires pour JavaScript. Il peut exécuter des tests à la fois dans Node.js ou sur le navigateur. Il est utilisé dans le framework Angular et est particulièrement populaire dans les projets basés sur Angular. C'est un choix solide pour les projets Vanilla JS ou les projets basés sur d'autres frameworks également.
Le test de chemin heureux consiste à tester une méthode avec des entrées censées fonctionner normalement. Les arguments sont valables et dans des limites raisonnables. Ces tests vérifient si la méthode fait son travail correctement : les cas de test doivent être des exemples simples de la façon dont la méthode est expliquée dans sa documentation.
Exemples de pseudocodes :
expect(add(2, 2)).toBe(4)
,
expect(concatenate(“Lorem”, “Ipsum”)).toBe(“LoremIpsum”)
Ces tests sont destinés à le détecter automatiquement chaque fois que le comportement de la clé de méthode est interrompu.
Voyons quelques méthodes simples : des opérations simples dont nous pourrions avoir besoin dans certaines applications du monde réel.
Toutes les implémentations sont grandement simplifiées : toutes les méthodes échoueront de manière laides si seulement nous leur fournissons des paramètres légèrement différents de ceux attendus. Le code est loin d'être robuste.
Méthode qui accueille l'utilisateur avec son nom et son prénom :
export function greet(name, surname) { return `Hello ${name} ${surname}!`; }
shortDate
est une méthode de formatage qui prend un objet date et le renvoie formaté sous forme de chaîne courte. Le code:
export function shortDate(date) { return date.toISOString().substring(0, 10); }
ellipsis
prennent une longue chaîne de texte et un paramètre de longueur facultatif, puis coupent la chaîne pour qu'elle s'adapte à la limite :
export function ellipsis(text, length = 50) { if (text.length > length) { return text.substring(0, length) + "…"; } return text; }
Méthode qui fournit des valeurs de chaîne traduites pour une paire key
et lang
. Il s'agit d'une implémentation simplifiée de ce qui pourrait être remplacé par des bibliothèques de traduction plus avancées.
export function translate(key, lang = "en") { switch (lang) { case "en": switch (key) { case "hello": return "Hello!"; } case "pl": switch (key) { case "hello": return "Cześć!"; } } }
Méthode pour appliquer un pourcentage de remise à un prix. Cela peut sembler excessif avec cette implémentation naïve, mais plus tard, lorsque nous commencerons à étudier les cas extrêmes, cela deviendra beaucoup plus intéressant.
export function applyDiscount(price, discountPercentage) { return price - (price * discountPercentage) / 100; }
Celui-ci calcule le prix total lors de l’achat de plusieurs unités à un prix donné. Cela deviendra également plus compliqué après l’ajout de cas extrêmes intéressants.
export function calculatePrice(unitPrice, quantity) { return unitPrice * quantity; }
Le code JS complet, 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; }
Pour ajouter Jasmine, commençons par convertir le dossier en package npm :
$ npm init -y Wrote to …/package.json: …
Ensuite, nous pouvons installer le package Jasmine :
$ 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
Ensuite nous pouvons générer les dossiers et fichiers utilisés par Jasmine :
$ npx jasmine init (no output)
Cette commande génère les éléments suivants :
spec/
—un dossier dans lequel nous pouvons mettre les fichiers *.spec.js
avec le test, et
spec/support/jasmine.json
— un fichier avec la configuration Jasmine.Pour les tests unitaires suivants, je me concentre uniquement sur le chemin heureux : je vérifie si le résultat est celui attendu pour des entrées raisonnables. Le test devrait être explicite, alors examinons-les :
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); }); }); });
(fichier spec/main.spec.js
)
Pour exécuter les tests, nous pouvons ajouter le script suivant à package.json
:
.. "scripts": { "test": "jasmine" }, …
Une fois cela en place, npm run test
exécute nos tests :
$ 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)
Dans cet article, nous avons examiné un exemple simple de code JS et comment il peut être couvert par des tests unitaires. Vous pouvez trouver l' exemple de code complet sur GitHub .
Également publié ici