Tests en JavaScript : Unit, Integration, E2E au niveau avancé

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : Pourquoi les tests avancés sont un must-have pour un projet JavaScript

Dans le développement moderne avec Node.js, les tests ne sont plus une étape optionnelle. Sans une couverture de code de qualité par des tests, toute refactorisation ou ajout de nouvelle fonctionnalité risque de se transformer en "roulette russe". Cependant, écrire simplement quelques assert ne suffit pas. Au niveau avancé, le développeur doit maîtriser trois couches principales : les tests unitaires (vérification de modules isolés), les tests d'intégration (interaction des composants, base de données, API) et les tests E2E (simulation des actions utilisateur). Dans cet article, nous allons analyser des techniques pratiques pour chaque couche en utilisant Node.js avec des outils modernes : Jest, Supertest et Playwright.



1. Tests unitaires : isolation, mocks et stubs au niveau avancé

Les tests unitaires vérifient le fonctionnement d'une seule fonction ou module en isolation des dépendances externes (base de données, système de fichiers, requêtes réseau). La tâche clé est de correctement moquer ces dépendances pour que le test soit rapide et déterministe.



Techniques avancées de mocking dans Jest

Prenons un exemple : une fonction qui accède à une API externe et met en cache le résultat dans Redis. Nous devons tester la logique de mise en cache sans effectuer de véritables requêtes.

// cacheService.jsconst axios = require('axios');const redis = require('redis');

class CacheService { constructor() { this.client = redis.createClient(); }

async fetchData(url) { const cached = await this.client.get(url); if (cached) return JSON.parse(cached);

const response = await axios.get(url); await this.client.setEx(url, 3600, JSON.stringify(response.data)); return response.data; }}

module.exports = CacheService;


// cacheService.test.jsconst CacheService = require('./cacheService');const axios = require('axios');const redis = require('redis');

jest.mock('axios');jest.mock('redis', () => ({ createClient: jest.fn(() => ({ get: jest.fn(), setEx: jest.fn() }))}));

describe('CacheService', () => { let service; let mockRedisClient;

beforeEach(() => { mockRedisClient = redis.createClient(); service = new CacheService(); });

test('should return cached data if present', async () => { const url = 'https://api.example.com/data'; const cachedData = { id: 1, value: 'cached' }; mockRedisClient.get.mockResolvedValue(JSON.stringify(cachedData));

const result = await service.fetchData(url);

expect(result).toEqual(cachedData); expect(axios.get).not.toHaveBeenCalled(); });

test('should fetch and cache data if not cached', async () => { const url = 'https://api.example.com/data'; const apiData = { id: 2, value: 'fresh' }; mockRedisClient.get.mockResolvedValue(null); axios.get.mockResolvedValue({ data: apiData });

const result = await service.fetchData(url);

expect(result).toEqual(apiData); expect(mockRedisClient.setEx).toHaveBeenCalledWith(url, 3600, JSON.stringify(apiData)); });});

Points clés :

  • jest.mock('axios') mocke automatiquement tout le module axios.
  • Pour Redis, nous utilisons une fabrique qui retourne un mock avec les méthodes get et setEx.
  • Nous vérifions qu'en présence du cache, l'appel externe n'a pas lieu.


2. Tests d'intégration : tester l'interaction avec une vraie base de données et API

Les tests d'intégration vérifient comment différentes parties du système fonctionnent ensemble. Pour Node.js, cela signifie souvent tester les routes Express avec une base de données réelle (ou de test). Le meilleur outil est Supertest associé à Jest.



Configuration de la base de données de test et Supertest

Exemple : API pour la gestion des utilisateurs. Nous utilisons SQLite en mémoire pour l'isolation.

Blogs

Book Recommendations