Testing: @SpringBootTest vs @WebMvcTest
Choose the smallest context that proves your code works, and mock the rest.
Open this lesson in the learning hubKey points
- Plain unit tests need no Spring. If a class has no annotations in its logic, just call
new. @WebMvcTestloads only the web layer: one controller, JSON, validation, error handling. It is fast.- In a slice, collaborators are absent — supply them with
@MockitoBean(this replaced the deprecated@MockBean). @SpringBootTeststarts the whole context. Use it sparingly, for wiring and end-to-end checks.- Add
webEnvironment = RANDOM_PORTand injectTestRestTemplatefor a real HTTP round trip. @DataJpaTestslices to JPA and rolls back each test. Point it at Testcontainers, not H2, to test real SQL.
Example
@WebMvcTest(OrderController.class) // web layer only
class OrderControllerTest {
@Autowired MockMvc mvc;
@MockitoBean OrderService service; // the service is faked
@Test
void returnsOrder() throws Exception {
given(service.find(7L))
.willReturn(new OrderResponse(7L, "PAID", new BigDecimal("42.00")));
mvc.perform(get("/api/orders/7"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value("PAID"));
}
@Test
void rejectsInvalidBody() throws Exception {
mvc.perform(post("/api/orders")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"customerEmail\":\"not-an-email\"}"))
.andExpect(status().isBadRequest());
}
}
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class ShopApplicationIT {
@Autowired TestRestTemplate rest;
@Test
void contextLoadsAndServes() {
assertThat(rest.getForEntity("/actuator/health", String.class)
.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}
Slice tests for speed, one full-context test for confidence — not the other way round.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Boot course, and every lesson in it is listed on the Spring Boot contents page.