Когда речь идет о Spring MVC и наших REST-контроллерах, важно убедиться, что приложение корректно обрабатывает все запросы. Представьте, что ваш контроллер должен выполнять такую сложную задачу, как прием запроса о заказе пиццы, но вместо этого отправляет вам хачапури. MockMvc позволяет протестировать такие сценарии (ну, не про пиццу, а про правильность обработки запросов).
MockMvc помогает:
- Проверить правильность маршрутов (например,
GET /api/orders/{id}). - Убедиться, что эндпоинты возвращают корректные HTTP-статусы (200, 404).
- Проверить, что тело ответа содержит именно то, что ожидается (JSON, XML и т.д.).
- Ловить баги ещё до того, как кто-то из 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("Привет, мир!")); // Проверяем, что тело ответа содержит "Привет, мир!"
}
}
Разберем, что здесь происходит:
mockMvc.perform(get("/api/hello"))— имитируем HTTP GET-запрос.andExpect(status().isOk())— проверяем, что возвращается HTTP-статус 200.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, убедитесь, что:
- Вы корректно указываете маршруты. Часто забывают выставить базовый
@RequestMappingв контроллере. - Заголовки и типы контента соответствуют тому, что ожидает ваш эндпоинт. Например, если вы передаете JSON, не забудьте про
contentType(MediaType.APPLICATION_JSON).
Если MockMvc выдает ошибку, что не может найти контроллер, проверьте, настроена ли аннотация @SpringBootTest и есть ли ваш контроллер в контексте приложения.
MockMvc стал вашим первым шагом к безупречно протестированным контроллерам. В следующих лекциях мы углубимся в написание более сложных тестов и изучим интеграцию с реальными базами данных.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ