Tests en JavaScript : des tests unitaires aux tests de bout en bout
\n\nDes tests de qualité sont une partie essentielle du développement professionnel en JavaScript. Dans cet article, nous aborderons les trois principaux niveaux de tests : les tests unitaires (unit), les tests d'intégration (integration) et les tests de bout en bout (e2e). Vous découvrirez quels outils utiliser, comment écrire des tests sur Node.js et comment construire une stratégie de test efficace.
\n\n1. Tests unitaires : la base de la pyramide des tests
\n\nLes tests unitaires vérifient des modules isolés — fonctions, classes ou méthodes individuelles. La règle principale : le code testé ne doit pas dépendre de ressources externes (base de données, API, système de fichiers).
\n\nOutils pour les tests unitaires
\n- \n
- Jest — le framework le plus populaire de Facebook. Il inclut nativement les mocks, les snapshots et la couverture de code. \n
- Mocha + Chai — une combinaison flexible pour ceux qui aiment tout configurer manuellement. \n
- Vitest — un équivalent moderne de Jest, optimisé pour les projets Vite. \n
// Exemple de test unitaire avec Jest\nconst { calculateDiscount } = require('./pricing');\n\ndescribe('calculateDiscount', () => {\n test('retourne une réduction de 10% pour un montant > 1000', () => {\n const result = calculateDiscount(1500);\n expect(result).toBe(1350);\n });\n\n test('n'applique pas de réduction pour un montant <= 1000', () => {\n const result = calculateDiscount(500);\n expect(result).toBe(500);\n });\n\n test('gère la valeur limite de 1000', () => {\n const result = calculateDiscount(1000);\n expect(result).toBe(1000);\n });\n});\n\nMeilleures pratiques pour les tests unitaires
\n- \n
- Testez un seul comportement à la fois (une assertion par test). \n
- Utilisez des noms de tests descriptifs (given/when/then). \n
- Évitez de tester les méthodes privées — testez l'interface publique. \n
- Maintenez une couverture de code entre 70 et 80%. \n
2. Tests d'intégration : vérification de l'interaction des composants
\n\nLes tests d'intégration vérifient comment différents modules fonctionnent ensemble. Dans le contexte de Node.js, cela signifie généralement tester avec une vraie base de données, un système de fichiers ou des API externes.
\n\nScénarios typiques de tests d'intégration
\n- \n
- Interaction du contrôleur avec la couche service et la base de données. \n
- Vérification des middleware et des routes Express/Koa. \n
- Test des repositories avec une base de données de test (SQLite en mémoire ou PostgreSQL dans Docker). \n
// Exemple de test d'intégration avec Supertest et Jest\nconst request = require('supertest');\nconst app = require('../app');\nconst { createTestUser, cleanDatabase } = require('./helpers');\n\nbeforeEach(async () => {\n await cleanDatabase();\n});\n\ndescribe('POST /api/users', () => {\n test('crée un utilisateur et retourne 201', async () => {\n const response = await request(app)\n .post('/api/users')\n .send({ name: 'Ivan', email: 'ivan@test.com' });\n\n expect(response.status).toBe(201);\n expect(response.body).toHaveProperty('id');\n expect(response.body.name).toBe('Ivan');\n });\n\n test('retourne 400 en cas de doublon d'email', async () => {\n await createTestUser({ email: 'ivan@test.com' });\n\n const response = await request(app)\n .post('/api/users')\n .send({ name: 'Pierre', email: 'ivan@test.com' });\n\n expect(response.status).toBe(400);\n expect(response.body.error).toBe('Email déjà utilisé');\n });\n});\n\nConfiguration de l'infrastructure de test
\n- \n
- Docker Compose — pour lancer les services de test (BDD, Redis). \n
- Testcontainers — gestion programmatique des conteneurs depuis les tests. \n
- Bases de données en mémoire (par exemple, mongodb-memory-server) — pour des tests rapides sans dépendances externes. \n