Une femme devant son ordinateur portable en train de mordre un crayon

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

Coaching

À partir de 29€
  • Optimisation de code
  • Bonnes pratiques de développement
  • Montée en compétences rapide
Réserver une session
Écran d'ordinateur affichant des tests unitaires. Maîtriser les matchers Jest : La clé pour des tests plus précis

Apprenez à maîtriser les matchers Jest pour écrire des tests unitaires plus précis et efficaces. Découvrez les différents types de matchers et comment les utiliser pour améliorer la fiabilité de vos tests.

Fond GRIS avec LES lettres H T T P dans un style touche de clavier Comprendre les Méthodes de Requête HTTP

Découvrez les différentes méthodes de requête HTTP (GET, POST, PUT, DELETE, etc.) et apprenez quand les utiliser dans vos applications web.