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

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

Модуль 5. Spring
Рівень 9 , Лекція 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 став вашим першим кроком до бездоганно протестованих контролерів. У наступних лекціях ми заглибимося в написання більш складних тестів і вивчимо інтеграцію з реальними базами даних.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ