Lorsque vous écrivez des tests, il ne faut pas longtemps avant que vous ayez besoin de créer une version “fausse” d’un service interne — ou externe. Cela est communément appelé mocking. Vitest fournit des fonctions utilitaires pour vous aider à travers son assistant vi. Vous pouvez import { vi } from 'vitest' ou y accéder globalement (lorsque la configuration globale est activée).
Si vous souhaitez plonger directement, consultez la section API, sinon continuez à lire pour plonger plus profondément dans le monde du mocking.
Dates
Parfois, vous devez contrôler la date pour garantir la cohérence lors des tests. Vitest utilise le package @sinonjs/fake-timers pour manipuler les temporisateurs, ainsi que la date système. Vous pouvez en savoir plus sur l’API spécifique en détail ici.
Exemple
Fonctions
Le mocking des fonctions peut être divisé en deux catégories différentes : espionnage & mocking.
Parfois, tout ce dont vous avez besoin est de valider si une fonction spécifique a été appelée (et éventuellement quels arguments ont été passés). Dans ces cas, un espion serait tout ce dont nous avons besoin, que vous pouvez utiliser directement avec vi.spyOn() (lisez-en plus ici).
Cependant, les espions ne peuvent que vous espionner sur des fonctions, ils ne peuvent pas modifier l’implémentation de ces fonctions. Dans le cas où nous devons créer une version fausse (ou mockée) d’une fonction, nous pouvons utiliser vi.fn() (lisez-en plus ici).
Nous utilisons Tinyspy comme base pour le mocking des fonctions, mais nous avons notre propre wrapper pour le rendre compatible avec jest. Les deux vi.fn() et vi.spyOn() partagent les mêmes méthodes, cependant, seul le résultat de retour de vi.fn() est appelable.
Vous pouvez mocker des variables globales qui ne sont pas présentes avec jsdom ou node en utilisant l’assistant vi.stubGlobal. Cela mettra la valeur de la variable globale dans un objet globalThis.
Modules
Le mocking des modules observe des bibliothèques tiers, qui sont invoquées dans un autre code, vous permettant de tester des arguments, des sorties ou même de redéclarer son implémentation.
Consultez la section vi.mock() API pour une description plus détaillée de l’API.
Algorithme d’automocking
Si votre code importe un module mocké, sans aucun fichier associé __mocks__ ou factory pour ce module, Vitest mockera le module lui-même en l’invoquant et en mockant chaque export.
Les principes suivants s’appliquent :
Tous les tableaux seront vidés
Tous les primitifs et les collections resteront les mêmes
Tous les objets seront clonés en profondeur
Toutes les instances de classes et leurs prototypes seront clonés en profondeur
Modules Virtuels
Vitest prend en charge le mocking des modules virtuels Vite. Il fonctionne différemment de la façon dont les modules virtuels sont traités dans Jest. Au lieu de transmettre virtual: true à une fonction vi.mock, vous devez dire à Vite que le module existe sinon cela échouera lors de l’analyse. Vous pouvez le faire de plusieurs manières :
Fournir un alias
Fournir un plugin qui résout un module virtuel
L’avantage de la deuxième approche est que vous pouvez créer dynamiquement différents points d’entrée virtuels. Si vous redirigez plusieurs modules virtuels vers un seul fichier, alors tous seront affectés par vi.mock, alors assurez-vous d’utiliser des identifiants uniques.
Pièges du Mocking
Attention, il n’est pas possible de mocker les appels à des méthodes qui sont appelées à l’intérieur d’autres méthodes du même fichier. Par exemple, dans ce code :
Il n’est pas possible de mocker la méthode foo de l’extérieur car elle est référencée directement. Donc ce code n’aura aucun effet sur l’appel foo à l’intérieur de foobar (mais il affectera l’appel foo dans d’autres modules) :
Vous pouvez confirmer ce comportement en fournissant l’implémentation à la méthode foobar directement :
C’est le comportement prévu. C’est généralement un signe de mauvais code lorsque le mocking est impliqué de cette manière. Envisagez de refactoriser votre code en plusieurs fichiers ou d’améliorer l’architecture de votre application en utilisant des techniques telles que l’injection de dépendance.
Exemple
Système de Fichiers
Le mocking du système de fichiers garantit que les tests ne dépendent pas du système de fichiers réel, rendant les tests plus fiables et prévisibles. Cette isolation aide à éviter les effets secondaires des tests précédents. Elle permet de tester des conditions d’erreur et des cas limites qui pourraient être difficiles ou impossibles à reproduire avec un système de fichiers réel, tels que des problèmes de permission, des scénarios de disque plein ou des erreurs de lecture/écriture.
Vitest ne fournit aucune API de mocking du système de fichiers par défaut. Vous pouvez utiliser vi.mock pour moquer manuellement le module fs, mais c’est difficile à maintenir. Au lieu de cela, nous recommandons d’utiliser memfs pour le faire pour vous. memfs crée un système de fichiers en mémoire, qui simule les opérations du système de fichiers sans toucher au disque réel. Cette approche est rapide et sûre, évitant tout potentiel effet secondaire sur le système de fichiers réel.
Exemple
Pour rediriger automatiquement chaque appel fs vers memfs, vous pouvez créer les fichiers __mocks__/fs.cjs et __mocks__/fs/promises.cjs à la racine de votre projet :
Parce que Vitest s’exécute dans Node, le mocking des requêtes réseau est délicat ; les API Web ne sont pas disponibles, donc nous avons besoin de quelque chose qui imite le comportement du réseau pour nous. Nous recommandons Mock Service Worker pour accomplir cela. Il vous permettra de mocker à la fois les requêtes réseau REST et GraphQL, et est indépendant des frameworks.
Mock Service Worker (MSW) fonctionne en interceptant les requêtes que vos tests font, vous permettant de l’utiliser sans changer aucun de votre code d’application. Dans le navigateur, cela utilise l’API Service Worker. Dans Node.js, et pour Vitest, cela utilise la bibliothèque @mswjs/interceptors. Pour en savoir plus sur MSW, lisez leur introduction
Configurer le serveur avec onUnhandleRequest: 'error' garantit qu’une erreur est lancée chaque fois qu’il y a une requête qui n’a pas de gestionnaire de requête correspondant.
Plus
Il y a beaucoup plus à MSW. Vous pouvez accéder aux cookies et aux paramètres de requête, définir des réponses d’erreur fictives, et bien plus encore ! Pour voir tout ce que vous pouvez faire avec MSW, lisez leur documentation.
Temporisateurs
Lorsque nous testons du code qui implique des délais ou des intervalles, au lieu de faire attendre nos tests ou de provoquer un délai d’attente, nous pouvons accélérer nos tests en utilisant des temporisateurs “faux” qui moquent les appels à setTimeout et setInterval.
Consultez la section vi.useFakeTimers API pour une description plus détaillée de l’API.
Exemple
Fiche de Révision
vi dans les exemples ci-dessous est importé directement depuis vitest. Vous pouvez également l’utiliser globalement, si vous définissez globals sur true dans votre config.
Je veux…
Espionner une méthode
Mock des variables exportées
Mock d’une fonction exportée
Exemple avec vi.mock :
Exemple avec vi.spyOn :
Mock d’une implémentation de classe exportée
Exemple avec vi.mock et .prototype:
Exemple avec vi.mock et une valeur de retour :
Exemple avec vi.spyOn:
Espionner un objet retourné par une fonction
Exemple en utilisant le cache :
Mock d’une partie d’un module
Mock de la date actuelle
Pour simuler le temps de Date, vous pouvez utiliser la fonction d’assistance vi.setSystemTime. Cette valeur ne se réinitialise pas automatiquement entre les différents tests.
Attention, l’utilisation de vi.useFakeTimers change également le temps de Date.
Mock d’une variable globale
Vous pouvez définir une variable globale en assignant une valeur à globalThis ou en utilisant l’assistant vi.stubGlobal. Lorsque vous utilisez vi.stubGlobal, elle ne se réinitialise pas automatiquement entre les différents tests, sauf si vous activez l’option de configuration unstubGlobals ou appelez vi.unstubAllGlobals.
Mock de import.meta.env
Pour changer la variable d’environnement, vous pouvez simplement lui assigner une nouvelle valeur.
Si vous souhaitez réinitialiser automatiquement les valeurs, vous pouvez utiliser l’assistant vi.stubEnv avec l’option de configuration unstubEnvs activée (ou appeler manuellement vi.unstubAllEnvs dans un hook beforeEach) :