Pourquoi vos tests Java échouent (et comment y remédier)
\n\nVous avez écrit un code parfait. Le service fonctionne, la logique est impeccable, et les bugs ne se trouvent que dans les projets des autres. Mais quand vous lancez les tests... Là, une erreur de connexion à la BDD, ici, une API externe qui ne répond pas, et dans le troisième test, carrément une NullPointerException parce que la configuration ne s'est pas chargée correctement. Ça vous parle ?
\n\nLe problème, c'est que les tests classiques dépendent de l'environnement externe. Base de données, services REST, système de fichiers – tout cela rend les tests fragiles, lents et imprévisibles. La solution ? Les objets mock et les fixtures. Ce ne sont pas que des mots à la mode, mais des outils qui transforment le chaos en ordre.
\n\nDans cet article, nous allons voir comment utiliser correctement les mocks et les fixtures dans les tests Java avec des exemples concrets. Vous apprendrez la différence entre stub et mock, comment configurer des fixtures pour des scénarios complexes, et pourquoi Mockito est votre meilleur ami. C'est parti !
\n\nObjets mock : une simulation sans douleur
\n\nQu'est-ce qu'un mock et pourquoi en a-t-on besoin ?
\n\nUn objet mock est une imitation d'un composant réel qui se comporte comme vous le décidez. Au lieu de lancer une base de données ou d'appeler une API externe, vous créez un « faux » qui renvoie des données prédéfinies.
\n\nImaginez : vous testez un service qui envoie des notifications par email. Pour un vrai test, il faudrait lancer un serveur de messagerie, configurer SMTP, vérifier la file d'attente... Avec un objet mock, vous vérifiez simplement que le service a appelé la méthode d'envoi avec les bons paramètres. Rapide, propre, contrôlable.
\n\nMock vs Stub : quelle est la différence ?
\n\nLes débutants confondent souvent ces concepts. Mettons les points sur les i :
\n\n- \n
- Stub – renvoie des données fixes. Vous dites : « Quand la méthode getUser() est appelée, renvoie un objet User avec le nom "John" ». Le stub ne vérifie pas combien de fois il a été appelé. \n
- Mock – non seulement renvoie des données, mais vérifie aussi le comportement. Vous pouvez dire : « Assure-toi que la méthode sendEmail() a été appelée exactement une fois avec une adresse spécifique ». \n
En termes simples : le stub, c'est « donne-moi des données », le mock, c'est « donne-moi des données et vérifie comment on m'utilise ». En pratique, on utilise le plus souvent des objets mock, car ils offrent plus de contrôle.
\n\nÉcrire son premier mock avec Mockito
\n\nMockito est la bibliothèque de mocks la plus populaire en Java. Elle s'intègre avec JUnit 5 et Spring Boot, et sa syntaxe est si simple que vous la retiendrez en cinq minutes.
\n\nSupposons que vous ayez un service OrderService qui dépend d'un repository OrderRepository. Au lieu d'un repository réel, nous allons créer un mock :
import static org.mockito.Mockito.*;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n@ExtendWith(MockitoExtension.class)\npublic class OrderServiceTest {\n\n @Mock\n private OrderRepository orderRepository;\n\n @Test\n void testCreateOrder() {\n // Création de l'objet mock\n OrderService orderService = new OrderService(orderRepository);\n \n // Configuration du comportement du mock\n when(orderRepository.save(any(Order.class)))\n .thenReturn(new Order(1L, "test@example.com", 100.0));\n \n // Appel de la méthode testée\n Order result = orderService.createOrder("test@example.com", 100.0);\n \n // Vérification du résultat\n assertThat(result.getId()).isEqualTo(1L);\n // Vérification que la méthode save a été appelée exactement une fois\n verify(orderRepository, times(1)).save(any(Order.class));\n }\n}\n\nDans cet exemple, nous avons :
\n- \n
- Créé un mock pour
OrderRepositoryavec l'annotation@Mock. \n - Configuré que lors de l'appel à
save(), une commande pré-créée doit être retournée. \n - Vérifié