Framework de test avec mock Java Mockito

Java 常用类库Bibliothèques de classes courantes Java


Qu'est-ce que le test Mock ?

Dans le développement logiciel, les tests unitaires sont un moyen important de vérifier les fonctionnalités du code. Cependant, lorsque notre code dépend de systèmes externes (comme des bases de données, des services web, etc.), le tester directement peut poser plusieurs problèmes :

  1. Les dépendances externes peuvent être instables ou indisponibles
  2. La vitesse d'exécution des tests devient plus lente
  3. Il est difficile de simuler diverses conditions limites

Le test Mock (test de simulation) résout ces problèmes en créant des doublures pour les objets. Les objets Mock peuvent :

  • Simuler le comportement d'objets réels
  • Vérifier si les interactions se produisent comme prévu
  • Ne pas exécuter la logique réelle des objets réels

Pourquoi choisir Mockito ?

Mockito est actuellement le framework de test Mock le plus populaire de l'écosystème Java, et il présente les avantages suivants :

  1. API concise: Courbe d'apprentissage douce, prise en main facile
  2. Fonctionnalités puissantes: Prend en charge la vérification des appels de méthode, la configuration des valeurs de retour, la levée d'exceptions, etc.
  3. Bonne lisibilité: Le code de test est intuitif et facile à comprendre
  4. Communauté active: Mise à jour et maintenue en continu, avec une documentation complète

Concepts fondamentaux de Mockito

1. Création d'objets Mock

Exemple

// Méthode 1 : Utiliser une méthode statique
List mockedList = Mockito.mock(List.class);

// Méthode 2 : Utiliser des annotations (nécessite MockitoJUnitRunner)
@Mock
List mockedList;

2. Définition du comportement des méthodes

Exemple

// Renvoie 100 lorsque mockedList.size() est appelé
when(mockedList.size()).thenReturn(100);

// Renvoie "first" lorsque mockedList.get(0) est appelé
when(mockedList.get(0)).thenReturn("first");

// Lève une exception lorsque mockedList.get(1) est appelé
when(mockedList.get(1)).thenThrow(new RuntimeException());

3. Vérification des interactions

Exemple

// Vérifie que mockedList.add("one") a été appelé une fois
verify(mockedList).add("one");

// Vérifier que mockedList.clear() n'a jamais été appelé
verify(mockedList, never()).clear();

// Vérifier que mockedList.add("two") a été appelé au moins deux fois
verify(mockedList, atLeast(2)).add("two");

Exemples pratiques d'application de Mockito

Test du service utilisateur

Supposons que nous ayons unUserServicedépend deUserRepository:

Exemple

public class UserService {
    private UserRepository userRepository;
   
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
   
    public User getUserById(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException("Utilisateur introuvable"));
    }
}

Utilisez Mockito pour les tests :

Exemple

public class UserServiceTest {
    @Mock
    private UserRepository userRepository;
   
    @InjectMocks
    private UserService userService;
   
    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }
   
    @Test
    public void testGetUserById_Success() {
        // Préparer les données de test
        User mockUser = new User(1L, "testUser");
       
        // Configurer le comportement du mock
        when(userRepository.findById(1L))
            .thenReturn(Optional.of(mockUser));
       
        // Exécuter le test
        User result = userService.getUserById(1L);
       
        // Vérifier le résultat
        assertEquals("testUser", result.getUsername());
        verify(userRepository).findById(1L);
    }
   
    @Test(expected = UserNotFoundException.class)
    public void testGetUserById_NotFound() {
        when(userRepository.findById(2L))
            .thenReturn(Optional.empty());
       
        userService.getUserById(2L);
    }
}

Fonctionnalités avancées de Mockito

1. Matchers d'arguments

Exemple

// Tout argument entier
when(mockedList.get(anyInt())).thenReturn("element");

// Argument d'un type spécifique
when(mockedList.contains(anyString())).thenReturn(vrai);

// Matcher personnalisé
when(mockedList.add(argThat(arg -> arg.length() > 5))).thenReturn(vrai);

2. Vérification de l'ordre des appels

Exemple

InOrder inOrder = inOrder(mockedList);

inOrder.verify(mockedList).add("first");
inOrder.verify(mockedList).add("first");

3. Mock partiel (Spy)

Exemple

List real = new ArrayList();
List spyList = spy(realList);

// Appeler la méthode réelle
spyList.add("real");

// Mocker une méthode spécifique
doReturn(100).when(spyList).size();

Bonnes pratiques

  1. N'abusez pas des mocks: ne mockez que les dépendances nécessaires, gardez les tests réalistes
  2. Vérifiez les interactions avec modération: concentrez-vous sur les interactions importantes, ne vérifiez pas chaque appel de méthode
  3. Gardez les tests concis: chaque méthode de test ne doit tester qu'un seul point fonctionnel
  4. Organisez le code de test de manière raisonnable: utilisez @Before pour la configuration commune
  5. Combinez avec d'autres outils de test: à utiliser avec JUnit, AssertJ, etc.

Questions fréquemment posées (FAQ)

Q : quelle est la différence entre Mockito et PowerMock ?

R : Mockito est principalement utilisé pour simuler des objets ordinaires, tandis que PowerMock peut simuler des méthodes statiques, des constructeurs, etc. Cependant, PowerMock compromet l'isolation des tests, il est donc recommandé d'utiliser Mockito en premier.

Q : quand dois-je utiliser Spy au lieu de Mock ?

R : utilisez Spy lorsque vous avez besoin d'un comportement majoritairement réel et de ne modifier que quelques méthodes. Si vous avez besoin d'un contrôle total sur le comportement de l'objet, utilisez Mock.

Q : Mockito peut-il être utilisé pour des classes ou des méthodes finales ?

R : depuis Mockito 2.1.0, les classes et méthodes finales peuvent être mockées via la configuration, mais vous devez ajoutermockito-inlinedépendance.


Liens connexes

  1. Documentation officielle de Mockito
  2. Dépôt GitHub de Mockito

Java 常用类库Bibliothèques de classes courantes Java

Autres extensions