Maison > interface Web > js tutoriel > Unité, intégration et ETesting dans un exemple utilisant Jest

Unité, intégration et ETesting dans un exemple utilisant Jest

DDD
Libérer: 2024-11-20 19:53:15
original
313 Les gens l'ont consulté

Introduction

De nombreux développeurs sont confrontés à des défis lorsqu'il s'agit de tester leur code. Sans tests appropriés, des bogues peuvent passer, entraînant des utilisateurs frustrés et des correctifs coûteux.

Cet article vous montrera comment appliquer efficacement les tests unitaires, d'intégration et de bout en bout à l'aide de Jest, Supertest et Puppeteer sur un exemple très simple construit à l'aide de Node.js et MongoDB.

À la fin de cet article, j'espère que vous comprendrez clairement comment appliquer ces types de tests dans vos propres projets.

?‍? Veuillez trouver l'exemple complet ici dans ce dépôt.

Présentation de nos dépendances

Avant d'installer nos dépendances, permettez-moi d'abord de vous présenter notre exemple. Il s'agit d'un exemple très simple dans lequel un utilisateur peut ouvrir la page d'inscription, définir ses détails d'inscription, cliquer sur le bouton d'inscription et stocker ses informations dans la base de données.

Dans cet exemple, nous utiliserons les packages suivants :

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

La plupart de ces dépendances sont simples, mais voici des précisions pour quelques-unes d'entre elles :

  • puppeteer : vous permet de contrôler un navigateur sans tête (Chrome) pour des tests automatisés et du web scraping.
  • Jest-Puppeteer : Il est prédéfini pour Jest qui intègre Puppeteer, simplifiant la configuration pour exécuter des tests de bout en bout dans un environnement de navigateur. Vous pouvez l'utiliser comme préréglage dans le fichier jest.config.js et personnaliser le comportement de Puppeteer via un fichier appelé jest-puppeteer.config.js.
  • mongodb-memory-server : Il s'agit d'un utilitaire qui lance une instance MongoDB en mémoire pour des tests rapides et isolés des interactions avec la base de données.
  • npm-run-all : Un outil CLI pour exécuter plusieurs scripts npm en parallèle ou séquentiellement.

Tests unitaires

  • Définition : les tests unitaires se concentrent sur le test de composants ou de fonctions individuels de manière isolée. L'objectif est de vérifier que chaque unité de code fonctionne comme prévu.
  • Vitesse : les tests unitaires sont généralement très rapides car ils testent de petits morceaux de code sans recourir à des systèmes ou des bases de données externes.
  • Exemple : Dans notre exemple d'enregistrement d'utilisateur, un test unitaire peut vérifier la fonction qui valide une adresse e-mail. Par exemple, cela vérifierait que la fonction identifie correctement user@example.com comme valide tout en rejetant user@.com ou user.com.

Bien, traduisons cela en code.

Configuration de l'environnement de tests unitaires

Pour exécuter vos tests unitaires sans comportements imprévisibles, vous devez réinitialiser les fonctions fictives avant chaque test. Vous pouvez y parvenir en utilisant le hook beforeEach :

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Test de la validation des e-mails

Dans ce cas, nous souhaitons tester la fonction validateInput :

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

C'est une fonction très simple qui valide si l'entrée fournie contient un email valide. Voici son test unitaire :

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

await expect(async () => {}).rejects : sur la base de la documentation de Jest, c'est la façon d'attendre la raison d'une promesse rejetée.

Test des e-mails en double

Testons une autre fonction qui vérifie s'il y a un email dupliqué dans la base de données. En fait, celui-ci est intéressant car nous devons gérer la base de données, et en même temps, les tests unitaires ne doivent pas traiter de systèmes externes. Alors que devrions-nous faire alors ? Eh bien, nous devrions utiliser des Mocks.

Tout d’abord, jetez un œil à la fonction emailShouldNotBeDuplicate que nous devons tester :

// register.controller.js
const validator = require('validator');

const registerController = async (input) => {
  validateInput(input);
  ...
};

const validateInput = (input) => {
  const { name, email, password } = input;
  const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 });
  if (!isValidName) throw new Error('Invalid name');
  ...
};
Copier après la connexion
Copier après la connexion
Copier après la connexion

Comme vous le voyez, cette fonction envoie une requête à la base de données pour vérifier s'il y a un autre utilisateur ayant le même email. Voici comment nous pouvons nous moquer de l'appel à la base de données :

// __tests__/unit/register.test.js
const { registerController } = require('../controllers/register.controller');

describe('RegisterController', () => {
  describe('validateInput', () => {
    it('should throw error if email is not an email', async () => {
      const input = { name: 'test', email: 'test', password: '12345678' };
      await expect(async () => await registerController(input)).rejects.toThrow('Invalid email');
    });
  });
});
Copier après la connexion
Copier après la connexion

Nous nous sommes moqués (espionnés) de la méthode findOne de la base de données en utilisant jest.spyOn(object, methodName) qui crée une fonction simulée et suit ses appels. En conséquence, nous pouvons suivre le nombre d'appels et les paramètres transmis de la méthode findOne espionnée à l'aide de toHaveBeenNthCalledWith.

Tests d'intégration

  • Définition : les tests d'intégration évaluent la façon dont plusieurs composants fonctionnent ensemble. Il vérifie les interactions entre différentes fonctions, modules ou services.
  • Vitesse : les tests d'intégration sont plus lents que les tests unitaires car ils impliquent plusieurs composants et peuvent nécessiter un accès à la base de données ou des appels réseau.
  • Exemple : Pour le processus d'inscription de l'utilisateur, un test d'intégration pourrait vérifier que lors de l'envoi de la demande d'inscription, les données de l'utilisateur sont correctement validées et stockées dans la base de données. Ce test garantirait que tous les composants, tels que la validation des entrées, le point de terminaison de l'API et l'interaction avec la base de données, fonctionnent ensemble comme prévu.

Configuration de l'environnement de test d'intégration

Avant d'écrire notre test d'intégration, nous devons configurer notre environnement :

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
  • Comme vous le voyez, nous exportons la testingApp car nous en aurons besoin dans les tests d'intégration. Et nous l'exportons en tant que fonction car il est exporté avant d'être complètement initialisé, puisque beforeAll est asynchrone, l'instruction module.exports s'exécute avant que testingApp reçoive une valeur, ce qui la rend indéfinie lorsque nous essayons de l'utiliser dans notre test. fichiers.
  • En utilisant les hooks Jest, nous avons pu faire ce qui suit :
    • beforeAll : démarre le serveur Express et se connecte à la base de données MongoDB en mémoire.
    • afterAll : ferme le serveur Express et arrête la base de données MongoDB en mémoire en cours d'exécution.
    • beforeEach : nettoie la base de données en supprimant la collection d'utilisateurs avant chaque scénario de test.

Maintenant, nous sommes prêts à exécuter notre test d'intégration.

Test de la demande d'API d'enregistrement

Testons l'ensemble du processus d'inscription côté serveur : de l'envoi de la demande d'inscription au stockage des détails de l'utilisateur dans la base de données et à la redirection vers la page de réussite :

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Comme vous le voyez, la fonction registerController intègre plusieurs composants (fonctions), les fonctions validateInput, emailShouldNotBeDuplicate et createUser.

Alors, écrivons notre test d'intégration :

// register.controller.js
const validator = require('validator');

const registerController = async (input) => {
  validateInput(input);
  ...
};

const validateInput = (input) => {
  const { name, email, password } = input;
  const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 });
  if (!isValidName) throw new Error('Invalid name');
  ...
};
Copier après la connexion
Copier après la connexion
Copier après la connexion
  • Comme vous le voyez, dans ce cas de test, nous utilisons le package supertest pour envoyer une demande d'inscription à notre API. Cela simule le comportement réel de l'utilisateur pendant le processus d'inscription.
  • Dans ce cas, nous ne nous sommes pas moqués des appels à la base de données, car nous devons tester le comportement réel.

Tests de bout en bout (E2E)

  • Définition : les tests E2E simulent des scénarios d'utilisation réels pour valider l'ensemble du flux d'application du début à la fin. Il teste l'application dans son ensemble, y compris l'interface utilisateur et les services backend.
  • Vitesse : les tests E2E sont les plus lents parmi les trois types car ils impliquent de naviguer dans l'interface de l'application et d'interagir avec divers composants, nécessitant souvent plusieurs requêtes réseau.
  • Exemple : Dans le contexte de l'inscription d'un utilisateur, un test E2E simulerait un utilisateur ouvrant la page d'inscription, remplissant ses coordonnées (comme son nom, son e-mail et son mot de passe), en cliquant sur le bouton « S'inscrire » , puis en vérifiant s'ils sont redirigés vers une page de réussite. Ce test vérifie que chaque partie du processus d’inscription fonctionne de manière transparente du point de vue de l’utilisateur.

Reprenons notre exemple.

Configuration de l'environnement de test E2E

En fait, dans notre exemple, la configuration de l'environnement pour les tests de bout en bout est similaire à celle des tests d'intégration.

Tester le processus d'inscription du début à la fin

Dans ce cas, nous devons simuler exactement le comportement réel d'inscription d'un utilisateur, depuis l'ouverture de la page d'inscription, en remplissant ses coordonnées (nom, email, mot de passe), en cliquant sur le bouton « S'inscrire », et enfin en étant redirigé vers une page de réussite. . Jetez un œil au code :

npm install --save jest express mongoose validator
npm install --save-dev jest puppeteer jest-puppeteer mongodb-memory-server supertest npm-run-all
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Décomposons ce code :

  • Il existe de nombreux outils que vous pouvez utiliser pour mettre en œuvre vos tests de bout en bout. Ici, nous utilisons Jest avec Puppeteer pour mettre en œuvre nos tests de bout en bout.
  • Vous vous demandez peut-être ce qu'est une variable de page ? Comme Jest l'attend, il s'agit d'une variable globale fournie par Puppeteer, représentant un seul onglet dans un navigateur où nous pouvons effectuer des actions telles que naviguer et interagir avec des éléments.
  • Nous utilisons Puppeteer pour simuler le comportement de l'utilisateur en ouvrant cette page à l'aide de la fonction goto, en remplissant les entrées à l'aide de la fonction type, en cliquant sur le bouton d'enregistrement à l'aide de la fonction clic.

Exécuter tous les tests avec différentes configurations

Unit, Integration, and ETesting in One Example Using Jest

Photo de Nathan Dumlao sur Unsplash

À ce stade, vous vous demandez peut-être comment exécuter tous les types de tests simultanément lorsque chacun a sa propre configuration. Par exemple :

  • Dans les tests unitaires, vous devez réinitialiser tous les simulations avant chaque scénario de test, tandis que dans les tests d'intégration, cela n'est pas nécessaire.
  • Dans les tests d'intégration, vous devez configurer votre connexion à la base de données avant d'exécuter vos tests, mais dans les tests unitaires, cela n'est pas obligatoire.

Alors, comment faire pour exécuter tous les types de tests en même temps tout en s'assurant que chacun respecte sa configuration correspondante ?

Pour résoudre ce problème, suivez ces étapes :

1. Créons trois fichiers de configuration différents, jest.unit.config.js :

// setup.unit.js

beforeEach(() => {
  jest.resetAllMocks();
  jest.restoreAllMocks();
}); 
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

jest.integration.config.js :

// register.controller.js
const validator = require('validator');

const registerController = async (input) => {
  validateInput(input);
  ...
};

const validateInput = (input) => {
  const { name, email, password } = input;
  const isValidName = !!name && validator.isLength(name, { max: 10, min: 1 });
  if (!isValidName) throw new Error('Invalid name');
  ...
};
Copier après la connexion
Copier après la connexion
Copier après la connexion

jest.e2e.config.js :

// __tests__/unit/register.test.js
const { registerController } = require('../controllers/register.controller');

describe('RegisterController', () => {
  describe('validateInput', () => {
    it('should throw error if email is not an email', async () => {
      const input = { name: 'test', email: 'test', password: '12345678' };
      await expect(async () => await registerController(input)).rejects.toThrow('Invalid email');
    });
  });
});
Copier après la connexion
Copier après la connexion

2. Ensuite, mettez à jour vos scripts npm dans le fichier package.json comme suit :

// register.controller.js
const { User } = require('../models/user');

const registerController = async (input) => {
    ...
  await emailShouldNotBeDuplicated(input.email);
  ...
};

const emailShouldNotBeDuplicated = async (email) => {
  const anotherUser = await User.findOne({ email });
  if (anotherUser) throw new Error('Duplicated email');
};
Copier après la connexion

--config : Spécifie le chemin d'accès au fichier de configuration Jest.

npm-run-all --parallel : Permet d'exécuter tous les tests en parallèle.

3. Ensuite, créez trois fichiers d'installation nommés setup.unit.js, setup.integration.js et setup.e2e.js, contenant le code d'installation nécessaire utilisé dans les sections précédentes.
4. Enfin, exécutez tous les tests en exécutant cette commande npm run test. Cette commande exécutera tous les tests unitaires, d'intégration et de bout en bout en parallèle selon leurs configurations respectives.

Conclusion

Dans cet article, nous avons exploré les tests unitaires, d'intégration et de bout en bout (E2E), en soulignant leur importance pour la création d'applications fiables. Nous avons démontré comment implémenter ces méthodes de test à l'aide de Jest, Supertest et Puppeteer dans un exemple simple d'enregistrement d'utilisateur avec Node.js et MongoDB.

En fait, une stratégie de test solide améliore non seulement la qualité du code, mais renforce également la confiance des développeurs et la satisfaction des utilisateurs.

J'espère que cet article vous a fourni des informations utiles que vous pourrez appliquer à vos propres projets. Bon test !

Pensez-y

Si vous avez trouvé cet article utile, consultez également ces articles :

  • MongoDB GridFS simplifié
  • Comment j'ai amélioré le streaming vidéo avec FFmpeg et Node.js
  • 4 façons de gérer le JavaScript asynchrone

Merci beaucoup d'être resté avec moi jusqu'à présent. J'espère que vous apprécierez la lecture de cet article.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal