Fast, focused tests are what make Spring applications safe to change.
spring-boot-starter-test brings JUnit 5, AssertJ, Mockito and Spring's test support. Use three kinds of test:
- Plain unit tests for services: thanks to constructor injection,
new SignupService(fakeNotifier, clock)needs no Spring at all. These are the fastest and should be the majority. - Slice tests load only one layer.
@WebMvcTest(BookController.class)starts just the MVC infrastructure plus that controller and gives you aMockMvcto perform requests without a server. Its dependencies are replaced with mocks using@MockitoBean(Spring Framework 6.2+, replacing the deprecated@MockBean).@DataJpaTestsimilarly loads only JPA components with an embedded database, rolling back after each test. - Full integration tests with
@SpringBootTeststart the whole application context. AddwebEnvironment = RANDOM_PORTto run a real server and call it withTestRestTemplateorWebTestClient.
MockMvc asserts on status, headers and JSON with jsonPath("$.title").value("Dune"). Spring caches application contexts between tests with the same configuration, so keep test configurations consistent to avoid slow context restarts.
Name tests after behaviour, test HTTP contracts at the controller layer (status codes, validation, JSON shape) and business rules at the service layer.
Example
@WebMvcTest(BookController.class)
class BookControllerTest {
@Autowired MockMvc mvc;
@MockitoBean BookService service; // replaces the real bean with a mock
@Test
void returnsBookAsJson() throws Exception {
when(service.find(1L)).thenReturn(Optional.of(new Book(1, "Dune", "Herbert")));
mvc.perform(get("/api/books/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.title").value("Dune"));
}
@Test
void returns404WhenMissing() throws Exception {
when(service.find(9L)).thenReturn(Optional.empty());
mvc.perform(get("/api/books/9")).andExpect(status().isNotFound());
}
}
// static imports: MockMvcRequestBuilders.get, MockMvcResultMatchers.*, Mockito.whenRemember
- Unit-test services with plain
new; no Spring needed @WebMvcTest+ MockMvc tests controllers without a server@MockitoBeanswaps a bean for a Mockito mock@SpringBootTestloads everything; use it sparingly
Watch out for
- Using @SpringBootTest for every test, making the suite slow when slices or plain unit tests would do.