middle
Как тестировать контроллеры с помощью MockMvc и WebMvcTest?
@WebMvcTest — срезовая (slice) аннотация, которая поднимает только веб-слой Spring MVC: контроллеры, @ControllerAdvice, @JsonComponent, фильтры, WebMvcConfigurer. Сервисы, репозитории и прочие бины не загружаются — их нужно мокать.
MockMvc — утилита для тестирования контроллеров без запуска реального HTTP-сервера. Запросы обрабатываются через DispatcherServlet в имитированном окружении.
Пример теста контроллера
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void shouldReturnAllUsers() throws Exception {
List<UserDto> users = List.of(
new UserDto(1L, "Иван"),
new UserDto(2L, "Мария")
);
when(userService.findAll()).thenReturn(users);
mockMvc.perform(get("/api/users")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].name").value("Иван"))
.andExpect(jsonPath("$[1].name").value("Мария"));
}
@Test
void shouldCreateUser() throws Exception {
UserDto newUser = new UserDto(null, "Пётр");
UserDto savedUser = new UserDto(1L, "Пётр");
when(userService.create(any(UserDto.class))).thenReturn(savedUser);
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\": \"Пётр\"}"))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.name").value("Пётр"));
}
@Test
void shouldReturn404WhenUserNotFound() throws Exception {
when(userService.findById(999L))
.thenThrow(new UserNotFoundException(999L));
mockMvc.perform(get("/api/users/999"))
.andExpect(status().isNotFound());
}
}
WebMvcTest vs SpringBootTest + AutoConfigureMockMvc
| Критерий | @WebMvcTest |
@SpringBootTest + @AutoConfigureMockMvc |
|---|---|---|
| Контекст | Только MVC-слой | Полный контекст приложения |
| Скорость | Быстро | Медленнее |
| Зависимости | Нужно мокать через @MockBean |
Реальные бины доступны |
| Применение | Unit-тесты контроллеров | Интеграционные тесты |
На собеседовании: интервьюер ожидает понимание разницы между
@WebMvcTest(только MVC-слой) и@SpringBootTest+@AutoConfigureMockMvc(полный контекст). Частая ошибка — не мокать сервисы при@WebMvcTest, из-за чего тест падает сNoSuchBeanDefinitionException.