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