
Réaliser des tests d'intégration avec Jest
Publié le
Les tests d'intégration permettent de vérifier que plusieurs parties de votre code fonctionnent correctement ensemble. Jest fournit des outils spécifiques comme les mocks pour simuler certaines parties du code lors des tests d'intégration. Dans cet article, nous allons découvrir ces outils et apprendre à les utiliser efficacement pour créer des tests d'intégration.
🎯 Introduction aux mocks dans Jest
Qu'est-ce qu'un mock ?
Un mock est une simulation d'une partie de votre code. Il permet de remplacer une fonction ou un module par une version simplifiée pendant les tests. Par exemple, au lieu d'envoyer un vrai email dans vos tests, vous pouvez créer un mock qui simule l'envoi d'email.
Création d'un mock simple
Pour créer un mock avec Jest, on utilise la fonction jest.fn()
. Cette fonction crée une simulation de fonction que l'on peut suivre et contrôler dans nos tests. Voici un exemple :
const sendEmail = jest.fn();
// Utilisation du mock
sendEmail('hello@example.com');
// Vérification que la fonction a été appelée
expect(sendEmail).toHaveBeenCalled();
expect(sendEmail).toHaveBeenCalledWith('hello@example.com');
Dans cet exemple :
- jest.fn()
crée une fonction simulée
- Cette fonction enregistre automatiquement chaque appel fait à elle
- Nous pouvons vérifier si et comment elle a été appelée
Contrôler le comportement d'un mock
Les mocks peuvent aussi renvoyer des valeurs spécifiques. On utilise mockReturnValue
ou mockResolvedValue
pour les promesses :
// Mock qui renvoie une valeur simple
const getName = jest.fn().mockReturnValue('John');
console.log(getName()); // Affiche 'John'
// Mock qui renvoie une promesse
const fetchData = jest.fn().mockResolvedValue({ id: 1, name: 'John' });
await fetchData(); // Renvoie { id: 1, name: 'John' }
🛠️ Simulation de modules complets
La fonction jest.mock()
jest.mock()
permet de simuler un module entier. C'est utile quand vous voulez remplacer toutes les fonctions d'un service. Voici comment ça marche :
1. Définition du service
// emailService.js
class EmailService {
sendWelcome(email) {
// Code pour envoyer un vrai email
}
}
Ici, nous avons une classe EmailService
qui contient une méthode pour envoyer un email de bienvenue.
2. Simulation avec jest.mock()
// test.js
jest.mock('./emailService');
// Toutes les fonctions de EmailService sont maintenant des mocks
const EmailService = require('./emailService');
const emailService = new EmailService();
Avec jest.mock('./emailService')
, Jest remplace automatiquement toutes les fonctions du module par des mocks.
3. Configuration du mock
// On peut configurer le comportement du mock
emailService.sendWelcome.mockResolvedValue(true);
Grâce à cette configuration, sendWelcome
retourne une valeur résolue true
au lieu d'exécuter le code réel.
Avantages :
- - Jest remplace automatiquement toutes les fonctions du module par des mocks.
- - Vous pouvez ensuite configurer le comportement de ces fonctions.
- - Les vrais emails ne seront jamais envoyés pendant les tests.
Nettoyage des mocks
Entre chaque test, il faut nettoyer l'état des mocks avec clearAllMocks()
. Cela évite que les appels d'un test n'interfèrent avec un autre :
describe('Tests avec mocks', () => {
beforeEach(() => {
// Réinitialise tous les mocks avant chaque test
jest.clearAllMocks();
});
test('premier test', () => {
const mock = jest.fn();
mock();
expect(mock).toHaveBeenCalledTimes(1);
});
test('second test', () => {
const mock = jest.fn();
mock();
// Sans clearAllMocks, ce test pourrait échouer
expect(mock).toHaveBeenCalledTimes(1);
});
});
⚙️ Création d'un test d'intégration complet
Maintenant que nous comprenons les mocks, créons un vrai test d'intégration. Prenons l'exemple d'un service qui crée un utilisateur :
1. Implémentation du service
// userService.js
class UserService {
constructor(database, emailService) {
this.database = database;
this.emailService = emailService;
}
async createUser(userData) {
const user = await this.database.saveUser(userData);
await this.emailService.sendWelcome(user.email);
return user;
}
}
Ici, le service UserService
dépend d'une base de données et d'un service d'email pour créer un utilisateur et lui envoyer un email de bienvenue.
2. Configuration des mocks
// userService.test.js
const mockSaveUser = jest.fn();
const mockSendWelcome = jest.fn();
const database = { saveUser: mockSaveUser };
const emailService = { sendWelcome: mockSendWelcome };
const userService = new UserService(database, emailService);
Nous utilisons Jest pour créer des mocks des services externes, ce qui permet d'isoler notre test.
3. Mise en place du test
describe('UserService', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test("createUser enregistre l'utilisateur et envoie un email", async () => {
// Configurer les mocks
const userData = { name: 'John', email: 'john@example.com' };
mockSaveUser.mockResolvedValue({ id: 1, ...userData });
mockSendWelcome.mockResolvedValue(true);
Avant chaque test, nous réinitialisons les mocks pour éviter toute interférence entre les tests.
4. Exécution et validation du test
// Appeler la fonction à tester
const user = await userService.createUser(userData);
// Vérifier que tout s'est bien passé
expect(mockSaveUser).toHaveBeenCalledWith(userData);
expect(mockSendWelcome).toHaveBeenCalledWith('john@example.com');
expect(user).toEqual({
id: 1,
name: 'John',
email: 'john@example.com'
});
});
});
Nous testons ici que l'utilisateur est bien enregistré et qu'un email de bienvenue lui est envoyé.
Dans cet exemple :
- 1. Nous créons des mocks pour la base de données et le service d'email
- 2. Nous configurons leur comportement avec mockResolvedValue
- 3. Nous vérifions que les fonctions sont appelées correctement
- 4. Nous testons que le résultat final est correct
🔧 Conseils pratiques
- Créez des mocks uniquement pour les parties que vous ne voulez pas tester réellement (base de données, API externes, etc.)
- Utilisez beforeEach avec clearAllMocks pour avoir des tests indépendants
- Configurez vos mocks pour simuler aussi les cas d'erreur
- Vérifiez toujours que vos mocks sont appelés avec les bons paramètres