Mock en JavaScript : remplacer une dépendance le temps d'un test

Un mock remplace une dépendance réelle par un double contrôlé pendant un test : les quatre familles de doubles, vi.fn, vi.mock et l'horloge simulée.
3 min de lecture
Believemy logo

Tester une fonction qui envoie un e-mail pose un problème évident : personne ne veut mille messages partis pour de vrai à chaque exécution de la suite de tests.

La réponse tient en un mot : on remplace l'envoi par un double, et on vérifie qu'il a bien été sollicité.


Définition

Un mock est une fausse implémentation qui prend la place d'une dépendance réelle pendant un test. Elle rend une réponse décidée d'avance et enregistre tout ce qu'on lui demande : combien d'appels, avec quels arguments, dans quel ordre.

JAVASCRIPT
import { expect, it, vi } from "vitest";
import { notifier } from "./notifications.js";

it("envoie un message par destinataire", () => {
  const envoyer = vi.fn();

  notifier(["lea@exemple.com"], envoyer);

  expect(envoyer).toHaveBeenCalledTimes(1);
  expect(envoyer).toHaveBeenCalledWith("lea@exemple.com");
});

La fonction vi.fn() ne fait rien et rend undefined, ce qui suffit ici. Sa valeur est ailleurs : elle garde la trace de ses appels, et c'est cette trace que le test interroge.


Quatre doubles, souvent confondus

NomCe qu'il fait
EspionObserve les appels sans changer le comportement réel
BouchonRend une réponse fixée, sans aucune logique
MockUn bouchon dont les appels sont ensuite vérifiés
FauxUne implémentation simplifiée mais réellement fonctionnelle

Le vocabulaire courant appelle tout cela « mock », et ce raccourci est sans grande conséquence. La distinction utile reste celle du dernier : un faux, comme une base en mémoire, fonctionne vraiment, là où les trois autres se contentent de répondre.


Remplacer un module, arrêter le temps

Passer la dépendance en argument est la voie la plus simple, mais elle n'est pas toujours possible. Vitest sait aussi intercepter un import entier, et remplacer l'horloge du moteur.

JAVASCRIPT
vi.mock("./mailer.js", () => ({
  envoyer: vi.fn().mockResolvedValue({ id: "msg_1" }),
}));

vi.useFakeTimers();
relancerDansUneHeure();
vi.advanceTimersByTime(3600 * 1000);
expect(envoyer).toHaveBeenCalledTimes(1);
Bon à savoir

L'horloge simulée est le remède aux tests lents : sans elle, vérifier une relance planifiée avec setTimeout() obligerait à attendre réellement une heure.


Questions fréquentes

Question

Faut-il simuler toutes les dépendances ?

Non, seulement celles qui sortent du programme : réseau, disque, horloge, aléatoire, paiement. Une fonction de calcul importée par une autre n'a aucune raison d'être remplacée, et la remplacer ne fait que rendre le test aveugle à leur incompatibilité éventuelle.


Question

Que se passe-t-il quand la vraie dépendance change ?

C'est la faiblesse structurelle du procédé : le double continue de répondre comme avant, la suite reste verte, et la rupture n'apparaît qu'en production. Le garde-fou habituel est de compléter par quelques tests d'intégration qui, eux, appellent la vraie implémentation.


Question

Comment simuler un appel réseau ?

Deux écoles. La plus rapide remplace fetch() par un double qui rend une réponse toute faite. La plus fidèle intercepte la requête au niveau du réseau simulé, ce qui laisse passer le vrai code de l'Axios ou du client utilisé. La première suffit pour un test unitaire, la seconde vaut mieux dès qu'on veut vérifier des en-têtes ou un code d'erreur.

Termes connexes

Découvrez notre glossaire JavaScript

Tous les mots de JavaScript expliqués simplement : mots-clés, objets natifs, méthodes, erreurs et concepts. Définitions claires et exemples qui tournent, pour apprendre et pour se dépanner.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.