Framework de test avec mock Java Mockito
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 :
- Les dépendances externes peuvent être instables ou indisponibles
- La vitesse d'exécution des tests devient plus lente
- 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 :
- API concise: Courbe d'apprentissage douce, prise en main facile
- 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.
- Bonne lisibilité: Le code de test est intuitif et facile à comprendre
- Communauté active: Mise à jour et maintenue en continu, avec une documentation complète
Concepts fondamentaux de Mockito
1. Création d'objets Mock
Exemple
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
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
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
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
@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
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.verify(mockedList).add("first");
inOrder.verify(mockedList).add("first");
3. Mock partiel (Spy)
Exemple
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
- N'abusez pas des mocks: ne mockez que les dépendances nécessaires, gardez les tests réalistes
- Vérifiez les interactions avec modération: concentrez-vous sur les interactions importantes, ne vérifiez pas chaque appel de méthode
- Gardez les tests concis: chaque méthode de test ne doit tester qu'un seul point fonctionnel
- Organisez le code de test de manière raisonnable: utilisez @Before pour la configuration commune
- 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.