Mockito est un framework open source pour créer des objets mock dans les tests unitaires Java et Kotlin, qui permet d’isoler le code testé des dépendances externes. Grâce à lui, le développeur remplace les véritables référentiels, clients API et bases de données par des stubs contrôlés au comportement prédéfini. Selon Mockito.org, la bibliothèque est utilisée dans plus de 60% des projets Java qui pratiquent les tests unitaires.
Points clés
Mockito est une bibliothèque open source pour créer des objets mock (stubs) dans les tests unitaires pour Java, Kotlin et d’autres langages JVM. Contrairement à JUnit, qui est responsable de l’exécution des tests, Mockito résout le problème d’isolation — il remplace les dépendances réelles de la classe testée par des objets prévisibles.
Sans mocks, tester une méthode qui accède à une base de données ou à une API externe nécessite la mise en place d’un environnement réel — déploiement d’une base de données, démarrage d’un serveur. Mockito remplace ces dépendances par des objets au comportement fixe : la méthode repository.findById(1) retourne toujours un objet User donné sans accéder à la base de données.
L’architecture de Mockito est basée sur le pattern Proxy (pour les interfaces et les classes). La bibliothèque génère une sous-classe ou un proxy pour le type spécifié et intercepte tous les appels de méthodes, retournant des valeurs par défaut ou des valeurs définies via when().thenReturn().
Le principe de fonctionnement de Mockito repose sur trois opérations de base : création du mock, configuration du comportement (stubbing) et vérification des appels (verification). Chaque opération utilise des méthodes statiques de la classe org.mockito.Mockito — la classe la plus téléchargée de l’écosystème Java selon les statistiques de Maven Central. Tous les appels de méthodes du mock sont enregistrés en mémoire, ce qui permet de les vérifier ultérieurement via verify.
Un test typique avec Mockito comprend trois phases : Arrange — création des mocks et configuration des stubs via when().thenReturn(), Act — appel de la méthode testée, Assert — vérification du résultat via assertEquals et verify(mock). Cette approche est appelée AAA (Arrange-Act-Assert).
Prenons un test simple où Mockito remplace un référentiel d’utilisateurs. La méthode when().thenReturn() configure le mock pour que l’appel à findById retourne un objet User préalablement préparé.
// Création d’un mock de référentiel
UserRepository mockRepo = mock(UserRepository.class);
// Configuration du comportement : findById(1) retourne un utilisateur
when(mockRepo.findById(1)).thenReturn(new User("Alice"));
// Vérification que la méthode a bien été appelée
User result = mockRepo.findById(1);
assertEquals("Alice", result.getName());
verify(mockRepo).findById(1);
Mockito propose deux façons de créer des mocks : la méthode statique mock(Class) et l’annotation @Mock avec initialisation via MockitoAnnotations.openMocks(). La première approche est compacte pour un ou deux mocks, la seconde est pratique quand il y a beaucoup de dépendances — les annotations réduisent le code boilerplate.
La méthode mock() prend une classe et retourne un objet stub qui peut être configuré via when().thenReturn(). Toutes les méthodes non configurées retournent des valeurs par défaut : 0 pour les nombres, false pour boolean, null pour les objets.
ApiClient apiClient = mock(ApiClient.class);
Database database = mock(Database.class);
L’annotation @Mock combinée avec @ExtendWith(MockitoExtension.class) crée automatiquement des mocks pour tous les champs de la classe de test. MockitoExtension est responsable de l’initialisation avant chaque test.
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void getUserShouldReturnUserFromRepo() {
when(userRepository.findById(1)).thenReturn(new User("Alice"));
User result = userService.getUser(1);
assertEquals("Alice", result.getName());
}
}
Stubbing est le processus de définition de ce qu’une méthode mock doit retourner lorsqu’elle est appelée avec des arguments spécifiques. La syntaxe de base : when(mock.method(args)).thenReturn(value). Pour différents scénarios, Mockito propose plusieurs variantes de méthodes then.
| Méthode | Objectif |
|---|---|
| thenReturn(value) | Retourne toujours la valeur spécifiée |
| thenThrow(exception) | Lance une exception lors de l’appel |
| thenAnswer(answer) | Calcule la valeur de retour dynamiquement |
| thenCallRealMethod() | Appelle la méthode réelle (mock partiel) |
Lorsque la valeur de retour dépend des arguments d’appel, on utilise thenAnswer avec un lambda. C’est utile pour simuler le travail avec des données réelles — par exemple, générer un ID basé sur l’objet reçu.
when(repository.save(any())).thenAnswer(invocation -> {
User user = invocation.getArgument(0);
user.setId(42);
return user;
});
Verify est une fonctionnalité unique de Mockito que les anciennes bibliothèques d’objets mock (EasyMock, jMock) ne fournissent pas.
Verify rend les tests plus fiables car il vérifie non seulement la valeur de retour mais aussi les effets secondaires — les appels aux méthodes qui ne retournent pas de résultat (méthodes void). La méthode verify(mock).methodName(args) vérifie si une méthode spécifique du mock a été appelée avec les arguments indiqués. Cela permet de tester non seulement le résultat mais aussi le processus — le fait d’accéder à la dépendance.
Par défaut, verify vérifie que la méthode a été appelée exactement une fois. Si un nombre différent est nécessaire, on utilise times(n), atLeast(n), never() et d’autres modificateurs de la classe Mockito.
// Vérification du nombre d’appels
verify(repository, times(3)).save(any());
verify(repository, never()).delete(any());
verify(repository, atLeastOnce()).findById(1);
// Vérification de l’ordre des appels
InOrder inOrder = inOrder(repository);
inOrder.verify(repository).save(any());
inOrder.verify(repository).flush();
Lorsqu’on doit vérifier avec quel objet exact une méthode a été appelée, on utilise ArgumentCaptor. Il capture la valeur de l’argument pendant l’appel et permet de vérifier ses champs individuellement. ArgumentCaptor est particulièrement utile lorsque le code testé crée un objet en interne et le passe à une dépendance — vous ne pouvez pas vérifier cet objet autrement.
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Alice", captor.getValue().getName());
@Mock et @InjectMocks sont deux annotations clés de Mockito qui réduisent considérablement le code boilerplate. @Mock crée un mock pour un champ, et @InjectMocks injecte tous les mocks de la classe de test dans l’objet testé via le constructeur, le setter ou le champ.
Le mécanisme de @InjectMocks tente d’injecter les dépendances dans l’ordre suivant : constructeur avec le plus d’arguments, setter par type, champ privé. Si aucune de ces méthodes ne fonctionne, l’objet reste avec des dépendances null, et le test échouera avec une NullPointerException.
Il est important de comprendre : @InjectMocks n’analyse pas les types de champs — il substitue tout mock compatible par type. Si une classe a deux champs du même type, Mockito peut injecter le mauvais mock. Dans ce cas, il est recommandé d’utiliser un constructeur explicite avec des paramètres mock.
Dans le développement Android, Mockito est utilisé avec JUnit pour tester ViewModel, Repository et UseCase. Comme ces classes s’exécutent sur la JVM sans contexte Android, Mockito remplace leurs dépendances — Room DAO, Retrofit API, SharedPreferences — par des stubs au comportement prévisible.
Pour ajouter Mockito à un projet Android, il suffit d’ajouter la dépendance mockito-core ou mockito-inline (cette dernière prend en charge le mock des classes finales et des méthodes statiques). La version 5.12.0 (2024) inclut la prise en charge de Java 21 et une intégration améliorée avec JUnit 5.
// build.gradle.kts (module)
dependencies {
testImplementation("org.mockito:mockito-core:5.12.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
}
Auparavant, le mock des méthodes statiques et des constructeurs nécessitait PowerMock — une extension fonctionnant via l’instrumentation du bytecode. À partir de Mockito 5.x avec mockito-inline, cette capacité est intégrée directement : mockStatic(ClassName.class) permet de mocker les méthodes statiques sans bibliothèques supplémentaires.
Un scénario typique : un ViewModel appelle une méthode du référentiel et transforme le résultat en état d’interface utilisateur. Mockito remplace le référentiel, et le test vérifie que le ViewModel gère correctement la réponse de succès et l’erreur. En utilisant la Clean Architecture, des mocks sont créés pour chaque couche : DataSource, Repository et UseCase — cela permet de tester chaque couche isolément.
Questions fréquentes
Mockito est une bibliothèque pour Java et Kotlin qui utilise des proxies et la réflexion. MockK est une bibliothèque Kotlin-first avec prise en charge des coroutines, des fonctions d’extension et des classes finales sans configuration supplémentaire.
À partir de Mockito 2.1, le mock des classes finales est pris en charge via opt-in. Dans la version 5.x (mockito-inline), cela est activé par défaut. Il suffit d’ajouter la dépendance mockito-inline et d’utiliser la méthode standard mock().
Un Spy est un mock partiel qui par défaut appelle les méthodes réelles mais permet d’en remplacer certaines via when().thenReturn(). Spy est utile pour tester du code legacy lorsqu’on ne peut pas réécrire toute la classe.
thenReturn retourne toujours la même valeur, indépendamment des arguments. thenAnswer calcule la valeur de retour en fonction de l’invocation — arguments d’appel, le mock lui-même et l’état. Pour les réponses dynamiques, utilisez toujours thenAnswer.
Verify vérifie non seulement le résultat mais aussi le processus — le fait d’accéder à la dépendance. C’est crucial pour les services qui doivent sauvegarder des données ou envoyer des notifications. Sans verify, le test ne détectera pas qu’une méthode n’a pas appelé save() ou send().
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi