Pourquoi tester ? Premiers tests avec node:assert

Première leçon du cours Tests automatisés, en accès libre : environ 15 minutes, 3 exercices et 3 questions de quiz. C'est la leçon de base du catalogue ; dans l'espace étudiant, elle est réécrite pour ton profil.

Objectifs

  • Expliquer ce qu'apporte un test automatisé et situer les niveaux de la pyramide des tests
  • Écrire des assertions avec node:assert (strictEqual, deepStrictEqual, throws)
  • Choisir des cas de test pertinents, y compris les cas limites

AssertionsPyramide des testsCas limites

Vous corrigez un calcul de TVA, tout semble fonctionner… et trois semaines plus tard, quelqu’un découvre que les remises ne s’appliquent plus. Un test automatisé est un petit programme qui exécute votre code et vérifie qu’il produit le résultat attendu. Lancé à chaque modification, il détecte ces régressions en quelques secondes.

Les tests apportent aussi :

  • de la confiance pour refactoriser : on peut réorganiser le code sans peur ;
  • une documentation vivante : les tests montrent comment utiliser une fonction ;
  • un meilleur design : un code difficile à tester est souvent trop couplé.

La pyramide des tests

Niveau Ce qu’on teste Vitesse Quantité
Unitaire Une fonction ou un module isolé Millisecondes Beaucoup
Intégration Plusieurs modules ensemble (route + base) Secondes Moyenne
Bout en bout (E2E) L’application entière via le navigateur Lent Peu

On commence par la base : les tests unitaires.

Les assertions avec node:assert

Node.js fournit le module node:assert. Une assertion vérifie une condition et lève une AssertionError si elle est fausse.

const assert = require("node:assert");

function prixTTC(ht, taux = 0.2) {
  if (ht < 0) throw new RangeError("Prix négatif");
  return Math.round(ht * (1 + taux) * 100) / 100;
}

// Valeurs simples : comparaison stricte (===)
assert.strictEqual(prixTTC(10), 12);
assert.strictEqual(prixTTC(10, 0.055), 10.55);

// Objets et tableaux : comparaison du contenu
assert.deepStrictEqual([1, 2].map((x) => x * 2), [2, 4]);

// Erreurs : on passe une FONCTION qui sera appelée par assert
assert.throws(() => prixTTC(-1), RangeError);

// Expressions régulières
assert.match("Commande #123", /#\d+/);

Attention à deux pièges :

  • assert.equal (non strict) utilise == : assert.equal(1, "1") passe. Préférez les variantes strictes, ou importez require("node:assert/strict").
  • assert.strictEqual({a: 1}, {a: 1}) échoue : deux objets distincts ne sont pas ===. Utilisez deepStrictEqual.

Choisir ses cas de test

Pour chaque fonction, posez-vous ces questions :

  1. Cas nominal : l’usage normal donne-t-il le bon résultat ?
  2. Cas limites : zéro, chaîne vide, tableau vide, un seul élément, valeurs maximales, arrondis.
  3. Entrées invalides : type incorrect, valeur négative, undefined.

Un message d’erreur clair aide énormément quand un test échoue :

assert.strictEqual(prixTTC(0), 0, "Un prix nul doit rester nul");

À retenir

Un test = préparer des données, appeler le code, vérifier le résultat. Utilisez les assertions strictes, testez les cas limites, et gardez des tests rapides et indépendants.

Exercices

Les solutions et les tests restent sur le serveur. Dans l'espace étudiant, ton code est exécuté et corrigé, et le tuteur donne des indices avant la solution.

  1. CodeDifficulté 1JavaScript dans le navigateur1 indice

    Premières assertions

    La fonction moyenne(notes) est fournie. Écrivez la fonction testerMoyenne() qui utilise assert pour vérifier :

    • moyenne([10, 20]) vaut 15 ;
    • moyenne([7]) vaut 7 ;
    • moyenne([]) lève une RangeError.

    Appelez ensuite testerMoyenne() en fin de fichier.

    function moyenne(notes) {
      if (notes.length === 0) throw new RangeError("Liste vide");
      return notes.reduce((a, b) => a + b, 0) / notes.length;
    }
    
    function testerMoyenne() {
      // Vos assertions ici
    }
    
    testerMoyenne();
  2. CodeDifficulté 2JavaScript dans le navigateur2 indices

    Un vérificateur qui attrape les bugs

    Écrivez verifierSlugify(slugify) qui reçoit une implémentation de slugify et lève une AssertionError si elle est incorrecte. Une implémentation correcte doit :

    • transformer "Bonjour le Monde" en "bonjour-le-monde" ;
    • retirer les espaces en début/fin : " Café " donne "cafe" (accents retirés) ;
    • renvoyer "" pour une chaîne vide.

    Le validateur passera de bonnes et de mauvaises implémentations à votre fonction.

    function verifierSlugify(slugify) {
      // Vos assertions sur slugify(...)
    }
  3. QCMDifficulté 11 indice

    Choisir la bonne assertion

    Quelle assertion vérifie que getUser() renvoie l’objet { id: 1, nom: "Ada" } ?

    • assert.strictEqual(getUser(), { id: 1, nom: "Ada" })
    • assert.deepStrictEqual(getUser(), { id: 1, nom: "Ada" })
    • assert.ok(getUser() == { id: 1, nom: "Ada" })

Quiz de fin de leçon

  1. Quel niveau de test doit être le plus nombreux ?

    • Les tests de bout en bout
    • Les tests unitaires
    • Les tests manuels
  2. Que fait assert.equal(1, "1") du module node:assert classique ?

    • Il échoue
    • Il passe, car il utilise ==
    • Il lève une TypeError
  3. Lequel est un cas limite pour une fonction de moyenne ?

    • [10, 20]
    • Un tableau vide
    • [12, 14, 16]

La suite du cours

  1. Le test runner de Node : organiser ses tests15 min
  2. Tests asynchrones et doublures (mocks, stubs, espions)18 min
  3. TDD et frameworks de test : Jest et Vitest18 min
  4. Tests d'intégration, couverture et intégration continue18 min

Tests automatisés · Intermédiaire · 2 h 54