JavaRush /Курсы /Модуль 5. Spring /Лекция 139: Практика: тестирование контроллеров с помощью...

Лекция 139: Практика: тестирование контроллеров с помощью MockMvc

Модуль 5. Spring
14 уровень , 8 лекция
Открыта

Если вы когда-нибудь хотели увидеть, как ваш API живет своей лучшей жизнью, но при этом не хотите запускать весь сервер и прикладывать руку к Postman, — MockMvc спешит на помощь. Сегодня мы углубимся в практическое использование MockMvc для тестирования контроллеров в вашем Spring-приложении.

MockMvc — это инструмент для тестирования Spring MVC. Он позволяет вам запускать HTTP-запросы к вашим контроллерам без необходимости поднимать реальный сервер. Другими словами, MockMvc — это ваш карманный Postman, но гораздо более интегрированный и нацеленный на автоматизацию. Используя MockMvc, вы можете с лёгкостью имитировать запросы, проверять ответы контроллеров, тестировать сценарии с ошибками и ловить HTTP-статусы.


Подготовка окружения

Перед тем как приступить к тестированию с помощью MockMvc, убедитесь, что ваше приложение настроено для работы с тестами. Для этого в build-файле вашего проекта (например, pom.xml, если используется Maven) должны быть добавлены зависимости:


<dependencies>
    <!-- Зависимость для Spring Boot Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Пример контроллера

Для тестирования мы будем использовать REST-контроллер, который обрабатывает сущность User. Вот как он может выглядеть:


@RestController
@RequestMapping("/api/users")
public class UserController {

    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable("id") Long id) {
        // Допустим, здесь вызывается сервис, который возвращает пользователя
        User user = new User(id, "John Doe");
        return ResponseEntity.ok(user);
    }

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        // Имитация создания пользователя
        return ResponseEntity.status(HttpStatus.CREATED).body(user);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable("id") Long id) {
        // Представим, что пользователь успешно удалён
        return ResponseEntity.noContent().build();
    }
}

Практика: тестируем контроллер с помощью MockMvc

Теперь займемся тестированием UserController. Тестировать будем основные методы: получение, создание и удаление пользователя.

Настройка MockMvc в тестах

В Spring Boot вы можете использовать аннотацию @WebMvcTest, чтобы поднять контекст только для тестирования веб-компонентов, таких как контроллеры.


@WebMvcTest(UserController.class) // Поднимаем контекст только для UserController
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc; // MockMvc позволяет отправлять запросы.

    @Test
    void testGetUserById() throws Exception {
        // Логика теста будет здесь
    }
}

Тестирование GET-запроса

Начнем с основного: тестируем, что контроллер корректно отвечает на запрос получения пользователя.


@Test
void testGetUserById() throws Exception {
    mockMvc.perform(get("/api/users/{id}", 1)) // Отправляем GET-запрос на эндпоинт.
            .andExpect(status().isOk()) // Проверяем, что статус ответа — 200 OK.
            .andExpect(content().contentType(MediaType.APPLICATION_JSON)) // Проверяем тип контента.
            .andExpect(jsonPath("$.id").value(1)) // Проверяем, что поле "id" равно 1.
            .andExpect(jsonPath("$.name").value("John Doe")); // Проверяем, что поле "name" равно "John Doe".
}

Здесь мы используем jsonPath, чтобы проверить содержимое JSON-ответа. Это невероятно удобно и позволяет работать даже с вложенными объектами.

Тестирование POST-запроса

Теперь добавим тест для метода создания пользователя.


@Test
void testCreateUser() throws Exception {
    mockMvc.perform(post("/api/users")
            .contentType(MediaType.APPLICATION_JSON)
            .content("{\"id\":1,\"name\":\"John Doe\"}")) // Отправляем POST-запрос с телом.
            .andExpect(status().isCreated()) // Ожидаем статус 201 Created.
            .andExpect(header().exists("Location")) // Проверяем, что есть заголовок Location.
            .andExpect(jsonPath("$.id").value(1))
            .andExpect(jsonPath("$.name").value("John Doe"));
}

Здесь вы видите, как легко можно передать тело запроса, указывая JSON-данные. Также мы проверяем наличие заголовка Location, часто используемого в ответах на POST-запросы.

Тестирование DELETE-запроса

Тестируем удаление пользователя. Здесь важно убедиться, что контроллер возвращает статус 204 No Content.


@Test
void testDeleteUser() throws Exception {
    mockMvc.perform(delete("/api/users/{id}", 1)) // Отправляем DELETE-запрос.
            .andExpect(status().isNoContent()); // Проверяем, что статус ответа — 204 No Content.
}

Тестирование негативных сценариев

Не всегда ваши эндпоинты отвечают успешно. Иногда они бросают ошибки, и эти сценарии также важно тестировать.

Предположим, что метод getUserById может выбросить исключение, если пользователя не существует:


@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable("id") Long id) {
    if (id < 0) {
        throw new UserNotFoundException("User not found");
    }
    User user = new User(id, "John Doe");
    return ResponseEntity.ok(user);
}

Вот пример теста для этого сценария:


@Test
void testGetUserNotFound() throws Exception {
    mockMvc.perform(get("/api/users/{id}", -1)) // Запрос с некорректным ID.
            .andExpect(status().isNotFound()) // Ожидаем статус 404 Not Found.
            .andExpect(jsonPath("$.error").value("User not found")); // Проверяем сообщение об ошибке.
}

Типичные ошибки и их устранение

Многие начинающие сталкиваются с проблемами при использовании MockMvc. Например, забывают указывать @WebMvcTest, и тогда тест начинает подтягивать зависимость от всей базы данных, сервисов и других компонентов приложения. Не забывайте настраивать MockMvc и изолировать тестируемые слои.

Еще одна распространенная ошибка — отсутствие параметров в запросах. К примеру, если вы забудете передать тело запроса в POST, MockMvc вернёт ошибку 400. Всегда пересматривайте, что требуется вашему эндпоинту.


Что дальше?

Тестирование с помощью MockMvc — это только один из этапов в цепочке обеспечения качества. В реальных проектах вы будете совмещать Unit, интеграционные и функциональные тесты для минимума багов и максимального спокойствия. Дальше в нашем курсе мы углубимся в интеграционное тестирование с MockMvc и подключение реальных баз данных через Testcontainers.

Для более детального погружения, вы можете ознакомиться с официальной документацией MockMvc.

Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Sauna Уровень 112
16 сентября 2025
В методе тестирования POST запроса дублируется учебный код из тестирования GET запроса