Testing with @SpringBootTest and @WebMvcTest

Spring Boot · Essentials · 15 min

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 a MockMvc to perform requests without a server. Its dependencies are replaced with mocks using @MockitoBean (Spring Framework 6.2+, replacing the deprecated @MockBean). @DataJpaTest similarly loads only JPA components with an embedded database, rolling back after each test.
  • Full integration tests with @SpringBootTest start the whole application context. Add webEnvironment = RANDOM_PORT to run a real server and call it with TestRestTemplate or WebTestClient.

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.when

Remember

  • Unit-test services with plain new; no Spring needed
  • @WebMvcTest + MockMvc tests controllers without a server
  • @MockitoBean swaps a bean for a Mockito mock
  • @SpringBootTest loads everything; use it sparingly

Watch out for

  • Using @SpringBootTest for every test, making the suite slow when slices or plain unit tests would do.

Check yourself

  1. What does @WebMvcTest(BookController.class) load?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.spring.io/spring-boot/reference/testing/spring-boot-applications.html