JavaRush /Курсы /Модуль 5. Spring /Лекция 138: Введение в MockMvc для тестирования MVC-контр...

Лекция 138: Введение в MockMvc для тестирования MVC-контроллеров

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

Когда речь идет о Spring MVC и наших REST-контроллерах, важно убедиться, что приложение корректно обрабатывает все запросы. Представьте, что ваш контроллер должен выполнять такую сложную задачу, как прием запроса о заказе пиццы, но вместо этого отправляет вам хачапури. MockMvc позволяет протестировать такие сценарии (ну, не про пиццу, а про правильность обработки запросов).

MockMvc помогает:

  1. Проверить правильность маршрутов (например, GET /api/orders/{id}).
  2. Убедиться, что эндпоинты возвращают корректные HTTP-статусы (200, 404).
  3. Проверить, что тело ответа содержит именно то, что ожидается (JSON, XML и т.д.).
  4. Ловить баги ещё до того, как кто-то из QA-тестировщиков найдет их и будет колоть вам больные места.

MockMvc является частью spring-test — библиотеки, которая входит в состав Spring Framework. То есть вам не нужно устанавливать ничего дополнительно, если вы уже работаете со Spring в вашем проекте.


Настройка MockMvc

Для начала разберемся, как подготовить окружение. Вы можете использовать аннотацию @AutoConfigureMockMvc, которая автоматически настраивает MockMvc для вашего приложения.

Пример настройки:


@SpringBootTest
@AutoConfigureMockMvc
public class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc; // MockMvc будет автоматически настроен

    // Тесты будут размещены здесь
}

Если вы чувствуете себя героем и хотите настроить все вручную, вот как это сделать:


@BeforeEach
void setUp() {
    mockMvc = MockMvcBuilders.standaloneSetup(new OrderController()).build();
}

Написание базового теста с MockMvc

Попробуем протестировать самый простой контроллер. Пусть у нас есть контроллер, который возвращает приветственное сообщение.


@RestController
@RequestMapping("/api/hello")
public class HelloController {

    @GetMapping
    public ResponseEntity<String> sayHello() {
        return ResponseEntity.ok("Привет, мир!");
    }
}

Теперь протестируем его:


@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testSayHello() throws Exception {
        mockMvc.perform(get("/api/hello")) // Имитируем GET-запрос
            .andExpect(status().isOk())    // Проверяем, что статус ответа 200
            .andExpect(content().string("Привет, мир!")); // Проверяем, что тело ответа содержит "Привет, мир!"
    }
}

Разберем, что здесь происходит:

  1. mockMvc.perform(get("/api/hello")) — имитируем HTTP GET-запрос.
  2. andExpect(status().isOk()) — проверяем, что возвращается HTTP-статус 200.
  3. andExpect(content().string("Привет, мир!")) — гарантируем, что тело ответа содержит ожидаемую строку.

Проверка JSON-ответов

Большая часть ваших контроллеров, вероятно, будет отдавать ответы в формате JSON. MockMvc позволяет работать с JSON очень удобно.

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


@RestController
@RequestMapping("/api/orders")
public class OrderController {

    @GetMapping("/{id}")
    public ResponseEntity<OrderDTO> getOrder(@PathVariable Long id) {
        OrderDTO order = new OrderDTO(id, "Pizza", 2); // Возвращаем "заглушечный" объект
        return ResponseEntity.ok(order);
    }
}

Пример DTO-класса:


public class OrderDTO {
    private Long id;
    private String name;
    private int quantity;

    // Конструкторы, геттеры, и сеттеры
}

Теперь напишем тест:


@SpringBootTest
@AutoConfigureMockMvc
public class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testGetOrder() throws Exception {
        mockMvc.perform(get("/api/orders/1")) // Имитируем GET-запрос
            .andExpect(status().isOk()) // Проверяем статус 200 OK
            .andExpect(jsonPath("$.id").value(1)) // Проверяем поле "id"
            .andExpect(jsonPath("$.name").value("Pizza")) // Проверяем поле "name"
            .andExpect(jsonPath("$.quantity").value(2)); // Проверяем поле "quantity"
    }
}

Ключевой момент здесь — jsonPath. Этот метод помогает извлекать значения из JSON-объектов и проверять их. Например:

  • $.id — это путь к полю id в корневом объекте.

Проверка HTTP-заголовков

Если ваш контроллер добавляет специальные заголовки в ответ, MockMvc и здесь приходит на помощь.

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


@RestController
@RequestMapping("/api/headers")
public class HeaderController {

    @GetMapping
    public ResponseEntity<String> getHeader() {
        return ResponseEntity.ok()
            .header("X-Custom-Header", "HeaderValue")
            .body("Ответ с заголовком");
    }
}

Тест:


@SpringBootTest
@AutoConfigureMockMvc
public class HeaderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testCustomHeader() throws Exception {
        mockMvc.perform(get("/api/headers"))
            .andExpect(status().isOk()) // Проверяем статус 200
            .andExpect(header().string("X-Custom-Header", "HeaderValue")); // Проверяем заголовок
    }
}

Обработка POST-запросов

Иногда нам нужно протестировать эндпоинты, которые принимают данные от клиента. Представим, что у нас есть контроллер, который обрабатывает создание новых заказов.

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


@RestController
@RequestMapping("/api/orders")
public class OrderController {

    @PostMapping
    public ResponseEntity<OrderDTO> createOrder(@RequestBody OrderDTO order) {
        order.setId(100L); // Устанавливаем ID созданного заказа
        return ResponseEntity.status(HttpStatus.CREATED).body(order);
    }
}

Тест:


@SpringBootTest
@AutoConfigureMockMvc
public class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testCreateOrder() throws Exception {
        String orderJson = "{ \"name\": \"Pizza\", \"quantity\": 1 }";

        mockMvc.perform(post("/api/orders")
                .contentType(MediaType.APPLICATION_JSON) // Указываем тип контента
                .content(orderJson)) // Передаем тело запроса
            .andExpect(status().isCreated()) // Проверяем статус 201 Created
            .andExpect(jsonPath("$.id").value(100)) // Проверяем, что ID установлен
            .andExpect(jsonPath("$.name").value("Pizza")) // Проверяем имя
            .andExpect(jsonPath("$.quantity").value(1)); // Проверяем количество
    }
}

Советы и типичные ошибки

Когда вы используете MockMvc, убедитесь, что:

  1. Вы корректно указываете маршруты. Часто забывают выставить базовый @RequestMapping в контроллере.
  2. Заголовки и типы контента соответствуют тому, что ожидает ваш эндпоинт. Например, если вы передаете JSON, не забудьте про contentType(MediaType.APPLICATION_JSON).

Если MockMvc выдает ошибку, что не может найти контроллер, проверьте, настроена ли аннотация @SpringBootTest и есть ли ваш контроллер в контексте приложения.


MockMvc стал вашим первым шагом к безупречно протестированным контроллерам. В следующих лекциях мы углубимся в написание более сложных тестов и изучим интеграцию с реальными базами данных.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ