Objectifs du chapitre :

  • Comprendre le concept de faux objets (mocking) et pourquoi il est utilisé dans les tests unitaires.
  • Introduction à la bibliothèque Mockito pour créer des mocks et des stubs.
  • Apprendre à créer et utiliser des mocks, des stubs, et des spies avec Mockito.
  • Utiliser les annotations @Mock, @InjectMocks, et @Spy pour simplifier la création de tests unitaires.

10.1 Introduction au mocking

Le mocking est une technique utilisée en développement logiciel pour simuler le comportement des objets complexes ou des objets externes (comme des services web, des bases de données) dans les tests unitaires. En utilisant des faux objets, vous pouvez isoler l'unité de code que vous testez et vérifier son comportement sans dépendre des implémentations externes.


10.2 Introduction à Mockito

Mockito est une bibliothèque Java populaire utilisée pour créer des mocks et des stubs dans les tests unitaires. Elle simplifie le processus de création de faux objets et permet de définir des comportements spécifiques pour les méthodes des objets simulés.

Installation de Mockito :

Pour utiliser Mockito dans votre projet, ajoutez la dépendance suivante à votre fichier pom.xml (pour Maven) ou build.gradle (pour Gradle).

Pour Maven :

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.5.1</version>
    <scope>test</scope>
</dependency>

Pour Gradle :

testImplementation 'org.mockito:mockito-core:4.5.1' 

10.3 Création de mocks et stubs

Mocks : Les mocks sont des objets simulés qui remplacent les objets réels dans les tests. Ils permettent de définir des comportements spécifiques pour les méthodes et de vérifier les interactions avec ces méthodes.

Stubs : Les stubs sont des mocks avec des comportements prédéfinis pour certaines méthodes. Ils renvoient des valeurs spécifiques lorsque ces méthodes sont appelées.

Exemple :

Classe à tester (UserService.java) :

public class UserService {
    private UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User getUserById(int id) {
        return userRepository.findById(id);
    }
}

Interface UserRepository.java :

public interface UserRepository {
    User findById(int id);
}

Classe de test (UserServiceTest.java) :

import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void testGetUserById() {
        User user = new User(1, "John Doe");
        when(userRepository.findById(1)).thenReturn(user);

        User result = userService.getUserById(1);

        assertEquals("John Doe", result.getName());
        verify(userRepository, times(1)).findById(1);
    }
}

Dans cet exemple, userRepository est simulé (mocked) et son comportement est défini pour renvoyer un objet User lorsque findById est appelé avec l'ID 1. Le test vérifie que getUserById renvoie le bon utilisateur et que findById est appelé exactement une fois.


10.4 Utilisation des annotations @Mock, @InjectMocks, et @Spy

@Mock : L'annotation @Mock est utilisée pour créer un mock de la classe ou de l'interface annotée.

@InjectMocks : L'annotation @InjectMocks est utilisée pour créer une instance de la classe et injecter automatiquement les mocks créés dans cette instance.

@Spy : L'annotation @Spy est utilisée pour créer une instance partielle du mock. Contrairement à @Mock, @Spy appelle les méthodes réelles de l'objet sauf si elles sont stubées.

Exemple détaillé :

Classe à tester (OrderService.java) :

public class OrderService {
    private PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public boolean processOrder(Order order) {
        return paymentService.processPayment(order.getAmount());
    }
}

Interface PaymentService.java :

public interface PaymentService {
    boolean processPayment(double amount);
}

Classe de test (OrderServiceTest.java) :

import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class OrderServiceTest {

    @Mock
    private PaymentService paymentService;

    @InjectMocks
    private OrderService orderService;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void testProcessOrder() {
        Order order = new Order(100.0);
        when(paymentService.processPayment(100.0)).thenReturn(true);

        boolean result = orderService.processOrder(order);

        assertTrue(result);
        verify(paymentService, times(1)).processPayment(100.0);
    }
}

Dans cet exemple, paymentService est simulé et injecté dans orderService. Le test vérifie que processPayment est appelé correctement et que la méthode processOrder retourne le bon résultat.


10.5 Bonnes pratiques avec Mockito

  1. Initialisation des mocks :

    • Utilisez MockitoAnnotations.openMocks(this) dans une méthode annotée avec @BeforeEach pour initialiser les mocks.
  2. Utilisation des spies :

    • Utilisez les spies avec précaution, car ils appellent les méthodes réelles sauf si elles sont stubées, ce qui peut entraîner des comportements inattendus.
  3. Vérification des interactions :

    • Utilisez verify pour vérifier que les méthodes des mocks sont appelées avec les bons arguments et le bon nombre de fois.
  4. Stubbing des méthodes :

    • Utilisez when pour définir le comportement des méthodes des mocks et thenReturn pour spécifier la valeur de retour.

Résumé du chapitre :

  • Le mocking est une technique essentielle pour tester les unités de code isolées en simulant les dépendances externes.
  • Mockito est une bibliothèque puissante et facile à utiliser pour créer des mocks et des stubs dans les tests unitaires.
  • Les annotations @Mock, @InjectMocks, et @Spy simplifient la création et l'injection des mocks.
  • Les bonnes pratiques avec Mockito incluent l'initialisation correcte des mocks, l'utilisation judicieuse des spies, et la vérification des interactions.
Modifié le: jeudi 18 juillet 2024, 05:26