🎯 OBJECTIF
Comprendre comment :
@SpringBootTest charge le contexte complet et quand l'utiliser@WebMvcTest isole la couche Web sans DB ni services réels@AutoConfigureMockMvc injecte MockMvc dans le contexte🧠 MODÈLE MENTAL
Les tests d'intégration Spring Boot existent sur un spectre : à un extrême, @WebMvcTest ne charge que la couche Web (controllers, Jackson, validation) avec les services mockés — rapide, ciblé. À l'autre extrême, @SpringBootTest démarre l'application complète avec toutes ses dépendances — lent mais réaliste. Testcontainers pousse le réalisme jusqu'à la base de données : un vrai PostgreSQL Docker, isolé, fidèle à la prod.
La règle de choix : utilise le contexte le plus petit qui te permet de tester ce que tu veux. Un bug dans la validation d'un controller n'a pas besoin d'une vraie DB. Un bug dans une requête JPQL n'a pas besoin d'un serveur HTTP. Le surcoût d'un contexte trop large se paie en minutes de CI chaque jour.
Démarre l'application Spring complète : tous les @Component, @Service, @Repository, configurations, sécurité, filtres, proxies AOP, transactions, Hibernate.
@SpringBootTest
@AutoConfigureMockMvc // ✓ injecte MockMvc pour tester les endpoints sans vrai serveur
class StockIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void should_call_endpoint() throws Exception {
mockMvc.perform(get("/stocks"))
.andExpect(status().isOk());
}
}javaWeb environments disponibles :
| Mode | Comportement | Client |
|---|---|---|
MOCK (défaut) |
Pas de vrai serveur HTTP | MockMvc |
RANDOM_PORT |
Vrai serveur Tomcat sur port aléatoire | TestRestTemplate / WebTestClient |
DEFINED_PORT |
Port configuré dans application.yml |
Rare en test |
🚨 @SpringBootTest sans @AutoConfigureMockMvc = pas de MockMvc
Sans @AutoConfigureMockMvc, le bean MockMvc n'existe pas et l'injection échoue. Les deux annotations vont toujours ensemble quand tu utilises MockMvc.
Charge uniquement la couche Web : controllers, config MVC, Jackson, validation. Ne charge pas : services, repositories, DB, sécurité complète.
@WebMvcTest(StockController.class)
class StockControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean // ✓ mock Spring-managed — injecté dans le contexte
private StockService service;
@Test
void should_return_stock() throws Exception {
when(service.findAll())
.thenReturn(List.of(new StockDto("TV")));
mockMvc.perform(get("/stocks"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].product").value("TV"));
}
}javaQuand choisir @WebMvcTest
Tester : mappings d'URL, validation Jakarta (@Valid), codes HTTP retournés, sérialisation JSON, gestion des erreurs (@RestControllerAdvice). Tout ce qui est dans la couche Web sans avoir besoin de la vraie logique métier.
Démarre un vrai PostgreSQL dans un conteneur Docker pour les tests. Isolé, fidèle à la prod, détecte les bugs que H2 manque.
@Testcontainers
@SpringBootTest
class StockIntegrationTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:15");
@DynamicPropertySource
static void configure(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Autowired
private MockMvc mockMvc;
@Test
void should_create_and_retrieve_stock() throws Exception {
// test end-to-end : HTTP → controller → service → repo → DB réelle
}
}javaContainer static — recommandé pour la performance
static sur le container = un seul démarrage pour toute la classe de test. Sans static, Docker démarre un nouveau container par test — x10 plus lent.
flowchart TD
Q{H2 dans les dépendances test ?}
Q -->|Oui| H2["H2 in-memory\n(datasource remplacée auto)"]
Q -->|Non| Q2{Testcontainers configuré ?}
Q2 -->|Oui| TC["PostgreSQL Docker\n(DynamicPropertySource)"]
Q2 -->|Non| REAL["Datasource de application.yml\n(vraie DB locale)"]mermaid| Contexte | Base utilisée |
|---|---|
@SpringBootTest + H2 en classpath |
H2 in-memory automatique |
@SpringBootTest sans H2 |
Datasource configurée dans application.yml |
@SpringBootTest + Testcontainers |
PostgreSQL Docker via @DynamicPropertySource |
@WebMvcTest |
Aucune — pas de JPA, pas de repository |
@DataJpaTest |
H2 par défaut ou datasource selon config |
🚨 Pointer vers une vraie DB locale sans le savoir
Si H2 n'est pas dans le classpath de test et que Testcontainers n'est pas configuré, @SpringBootTest utilise ta datasource application.yml. Tes tests peuvent modifier une vraie base locale sans que ce soit évident.
flowchart LR
U["Tests unitaires\n@ExtendWith(Mockito)\n~70%"] --> W
W["@WebMvcTest\nController layer\n~15%"] --> D
D["@DataJpaTest\nJPA layer\n~10%"] --> S
S["@SpringBootTest\n+ Testcontainers\nFlux critiques\n~5%"]mermaid| Niveau | Annotation | Coût | Quand l'utiliser |
|---|---|---|---|
| Unitaire | @ExtendWith(MockitoExtension) |
Bas | Logique métier, décisions, calculs |
| Controller | @WebMvcTest |
Moyen | Validation, mappings, codes HTTP |
| JPA | @DataJpaTest |
Moyen | Mappings Hibernate, dirty checking, cascade |
| Intégration complète | @SpringBootTest + Testcontainers |
Élevé | Flux critiques bout-en-bout |
⚡ TL;DR — chaque concept en une ligne
@SpringBootTest
✓ Contexte Spring complet — réaliste, proche prod, testable end-to-end avec MockMvc ou TestRestTemplate.
⚠ Lent — chaque @SpringBootTest rallonge la CI. Réserver aux flux critiques, pas à chaque service.
@WebMvcTest
✓ Couche Web uniquement — rapide, les services sont mockés via @MockBean, idéal pour la validation et les mappings.
⚠ Pas de DB, pas de JPA — si tu testes un service ou un repository, c'est le mauvais outil.
Testcontainers ✓ PostgreSQL Docker réel, isolé — détecte les bugs JSONB, UUID, séquences, plans d'exécution que H2 manque. ⚠ Requiert Docker et ralentit le build — réserver aux tests critiques ou à la CI, pas au dev local rapide.
Quelle base ?
✓ H2 présent → remplacé automatiquement. Testcontainers configuré → Docker injecté via @DynamicPropertySource.
⚠ Sans H2 ni Testcontainers → application.yml utilisé directement, risque de toucher une vraie DB.
🎓 À retenir
@MockBean vs @Mock — @MockBean crée un mock Spring-géré injecté dans le contexte (indispensable avec @WebMvcTest). @Mock est Mockito-only, sans contexte Spring. Utiliser @MockBean uniquement quand le contexte Spring est impliqué, sinon le coût est inutile.static et l'annoter @Container pour qu'il soit partagé entre tous les tests de la classe. Sans static, Docker redémarre à chaque méthode de test — catastrophique pour les temps de CI.@WebMvcTest ne charge pas la sécurité complète — les filtres de sécurité Spring Security sont partiellement configurés. Si ta sécurité est complexe, tester la couche sécurité séparément ou utiliser @SpringBootTest.