Projet numérologie : partie 5 / tests unitaires : js

Nous allons ajouter des tests unitaires à notre projet. Il existe de nombreuses bibliothèques de tests en javascript. Nous allons nous focaliser sur jest efficace et populaire.

Installation

Bibliothèque

On installe la bibliothèque pour le développement (on en aura pas besoin en production) :

npm install --save-dev jest

Si vous regardez le fichier package.json, vous voyez que jest est dans une section de dépendance spéciale, où sont listées les bibliothèque non utiles en production :

...
    "devDependencies": {
        "jest": "^29.5.0",
    }
...

Une valeur a été ajoutée : "devDependencies" pour distinguer les dépendances utiles en production ("dependencies") et celles utiles en développement. En tapant :

Voir la documentation pour de plus amples informations.

Exécutable

Puis on va l'utiliser pour lancer nos tests avec la commande npm run test. Pour cela, modifions l'entrée test du package.json pour :

...

"scripts": {

    ...

    "test": "jest",

    ...
}

...

L'exécutable jest est présent dans le dossier node_modules/.bin/. On peut alors l'exécuter :

vscode

Vous pouvez installer le plugin vscode-jest pour utiliser jest dans vscode. Nous allons ici tout faire en ligne de commande, mais c'est pratique et ça permet (entre autres) :

La palette de commande permet d'accéder à toutes les commandes du plugin en tapant jest

On installera également le module @types/jest pour que vscode fasse la completion automatique lorsque l'on code des tests : npm install --save-dev @types/jest (tips pris de ).

Par défaut jest va exécuter tous les fichiers :

Utilisation de jest

Fonctionnement

Essayons ça en créant un fichier __tests__/essais.js :

test('test vide', () => {
  expect(true).toBe(true);
});

Chaque test aura :

Exécution des tests

Puis exécutons le par les différentes manières possibles :

Changez ensuite le vrai en faux pour voir le test planter.

Import ES6

Par défaut, jestne fonctionne qu'avec les import commonJs de node. Pour utiliser les modules ES6 il faut le préciser à jest avec une variable d'environnement :

NODE_OPTIONS=--experimental-vm-modules npx jest

Modifiez le script d'exécution des tests package.json pour qu'il puisse utiliser les imports ES6.

Tests

Nous allons tester ici les fonctions de numérologie.js

Pour l'instant, le fichier numérologie exporte un objet contenant une référence vers la fonction chiffreAssocie. Exportons les 2 autres fonctions :

export default {
    chiffre: chiffreAssocie,
    nombre: nombre,
    somme: somme,
}
import numérologie from "../back/numérologie.js"

describe("Un chiffre associé à un prénom", () => {
    test("65 -> 6 + 5 = 11 -> 1 + 1 = 2", () => {
        expect(numérologie.somme(65)).toBe(6+5)
    })
    test("nombre associé au prénom d'une lettre", () => {
        expect(numérologie.nombre("A")).toBe(65)
    })
    test("nombre associé au prénom de plusieurs lettres", () => {
        expect(numérologie.chiffre("A")).toBe(2)
        expect(numérologie.chiffre("m")).toBe(1)
        expect(numérologie.chiffre("y")).toBe(4)
        expect(numérologie.chiffre("Amy")).toBe(2 + 1 + 4)
    })

})

Par défaut, on va grouper les tests similaire dans un même fichier. Si l'on a besoin de sous-groupes à l'intérieur d'un fichier, par exemple en faisant un groupe pour les tests d'une fonction, on peut utiliser un bloc describe.

Front

On peut tester de la même manière le js front. En revanche, on ne testera pas la manipulation de l'arbre DOM, il faut donc séparer les fichiers js en 2 types : ceux testables et les autres.

Les fichiers js testables sont ensuite importé directement dans les fichiers html avec un import classique.

Ici nous n'avons que ju javascript qui manipule l'arbre DOM, il est donc inutile de le tester.

Coverage

Pour savoir si nos tests couvrent bien l'ensemble du projet, c'est à dire si les tests passent bien par chaque ligne de code, on utilise des outils de couverture de code.

Avoir 100% de couverture de code ne signifie pas que votre projet est bien testé... Juste que les tests ont utilisé toutes les lignes de codes :

  • ça ne prouve pas que les fonctionnalités de votre code sont correctes
  • certaines fonctions n'ont pas besoin d'être testées (comme les constantes ou les affichages à l'écran par exemple)

Le code coverage est particulièrement utile pour savoir si on a bien testé ce else d'un if/then/else qui n'arrivent que rarement.

Il suffit de rajouter --coverageà jest pour qu'il fasse le coverage tout seul : npm test -- --coverage (ou ./node_modules/.bin/jest --coverage).

Modifions le test de chiffreAssocie pour s'en convaincre :

test("nombre associé au prénom de plusieurs lettres", () => {
    expect(numérologie.chiffreAssocie("")).toBe(0)
})

Ou ajoutons un fichier et voyons comme tout n'est pas testé :

__tests__/numérologie.js :

import numérologie from "../back/numérologie.js"
import db from "../db.js" // inutile. Juste pour voir le coverage

// ...

Mocker des fonctions

Concept avancé mais très utile lorsque l'on veut tester un comportement spécifique d'une fonction sans avoir à tout paramétrer. On va l'utiliser ici de façon un peut surfaite, mais pensez-y pour les tests de pannes, d'erreurs ou de fonction nécessitant le réseau.