Представим, что мы создаём микросервис, отвечающий за обработку заказов в онлайн-магазине. Он обрабатывает HTTP-запросы, вызывает сервисы для проверки наличия товаров на складе, взаимодействует с базой данных для сохранения информации о заказах. Всё это — набор взаимодействующих компонентов. И хотя вы протестировали их по отдельности в юнит-тестах, это ещё не гарантия, что всё работает вместе как надо. Именно тут вступает в игру интеграционное тестирование.
Интеграционное тестирование на уровне микросервиса позволяет:
- Проверить взаимодействие между контроллерами, сервисами, репозиториями и другими компонентами.
- Убедиться, что весь микросервис функционирует корректно, не потребляя реальные внешние зависимости.
- Эмулировать реальные HTTP-запросы и проверить, как приложение обрабатывает их, возвращая ответы.
MockMvc: ключевой инструмент для интеграционного тестирования
Прежде чем мы займёмся тестированием, давайте разберём, что такое MockMvc.
MockMvc — это удобный инструмент из Spring Test, который позволяет:
- Моделировать HTTP-запросы к вашему приложению без запуска реального web-сервера.
- Проверять, как ваш контроллер обрабатывает запросы, возвращает ответы и работает с внутренними сервисами.
- Симулировать реальные сценарии работы API, включая отправку параметров, тела запроса, настроек заголовков и многое другое.
Think about it like this: вместо того, чтобы собирать всю машину целиком и катать её по тестовой трассе, вы тестируете только её двигатель, но под нагрузкой, приближенной к реальной. Простыми словами: MockMvc позволяет протестировать веб-слой приложения изолированно, без необходимости поднимать весь сервер.
Почему MockMvc лучше для интеграционных тестов?
MockMvc предоставляет лёгкий способ тестирования:
- Быстрее, чем запуск полноценных интеграционных тестов с поднятием сервера. Это экономит время, особенно в больших проектах.
- Изолирует тестируемый слой. Если база данных или другие внешние системы не готовы, это не остановит тесты, ведь вы можете их замокать.
- Гибкий API. MockMvc позволяет легко отправлять запросы и проверять, как ваши контроллеры обрабатывают их.
Подготовка к работе с MockMvc
Прежде чем мы начнем погружаться в примеры, убедитесь, что ваш проект настроен для тестирования.
Для начала убедимся, что в вашем pom.xml (или build.gradle) добавлены тестовые зависимости:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Для работы с MockMvc вам понадобится следующая настройка в тестируемом классе:
@SpringBootTest // Поднимает контекст Spring для тестов
@AutoConfigureMockMvc // Включает автоматическую настройку MockMvc
Легко, да? Теперь ваш тестовый класс готов к работе.
Практика: Тестирование REST API с использованием MockMvc
Хватит теории, пора показать, как всё это работает на практике!
Предположим, у нас есть микросервис для управления книгами, с REST API для работы с коллекцией книг.
Контроллер для тестирования
Вот пример контроллера, который предоставляет HTTP-методы для работы с книгами:
@RestController
@RequestMapping("/books")
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
@GetMapping("/{id}")
public ResponseEntity<Book> getBook(@PathVariable Long id) {
return ResponseEntity.ok(bookService.findBookById(id));
}
@PostMapping
public ResponseEntity<Book> createBook(@RequestBody Book book) {
return ResponseEntity.status(HttpStatus.CREATED).body(bookService.saveBook(book));
}
}
У нас есть два метода:
GET /books/{id}— возвращает книгу по её идентификатору.POST /books— добавляет новую книгу.
Написание тестов для контроллера с MockMvc
Теперь напишем тесты для этого контроллера. Для начала создадим тестовый класс:
@SpringBootTest
@AutoConfigureMockMvc
class BookControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private BookService bookService; // Мокаем зависимость сервиса
@Test
void testGetBook() throws Exception {
// Данные для теста
Book book = new Book(1L, "The Hobbit", "J.R.R. Tolkien");
Mockito.when(bookService.findBookById(1L)).thenReturn(book);
// Отправляем GET запрос и проверяем результат
mockMvc.perform(get("/books/1"))
.andExpect(status().isOk()) // Ожидаем статус 200 OK
.andExpect(jsonPath("$.title").value("The Hobbit")) // Проверяем поле title
.andExpect(jsonPath("$.author").value("J.R.R. Tolkien")); // Проверяем поле author
}
@Test
void testCreateBook() throws Exception {
// Данные для теста
Book book = new Book(null, "1984", "George Orwell");
Book savedBook = new Book(2L, "1984", "George Orwell");
Mockito.when(bookService.saveBook(Mockito.any())).thenReturn(savedBook);
// Отправляем POST запрос с JSON-данными
String bookJson = """
{
"title": "1984",
"author": "George Orwell"
}
""";
mockMvc.perform(post("/books")
.contentType(MediaType.APPLICATION_JSON)
.content(bookJson))
.andExpect(status().isCreated()) // Ожидаем статус 201 Created
.andExpect(jsonPath("$.id").value(2L)) // Проверяем, что ID книги = 2
.andExpect(jsonPath("$.title").value("1984")) // Проверяем название
.andExpect(jsonPath("$.author").value("George Orwell")); // Проверяем автора
}
}
Что здесь происходит?
- Аннотации:
@SpringBootTestподнимает весь контекст Spring.@AutoConfigureMockMvcнастраивает MockMvc автоматически.@MockBeanсоздаёт мок для зависимостиBookService, который мы будем использовать для изоляции.
- Тесты:
- В
testGetBookмы мокаем методfindBookByIdв сервисе, чтобы он возвращал объектBook. Затем отправляем GET-запрос и проверяем, что ответ содержит правильные данные. - В
testCreateBookмы мокаем методsaveBook, отправляем POST-запрос с JSON-данными и проверяем, что ответ содержит данные созданной книги.
- В
- MockMvc API:
mockMvc.perform(...)выполняет HTTP-запрос.andExpect(...)содержит все проверки результата, от статуса ответа до содержимого JSON.
Типичные ошибки при использовании MockMvc
Итак, на что стоит обратить внимание:
- Не объявлена зависимость
MockMvcили@AutoConfigureMockMvc. В таком случае тесты не смогут использовать MockMvc. - Ошибки сериализации JSON. Проверьте, подключён ли Jackson к вашему проекту.
- Отсутствие моков для зависимостей. MockMvc тестирует только контроллер, так что обязательно мокаем сервисы через
@MockBean.
MockMvc — невероятно мощный инструмент для тестирования взаимодействия с вашими контроллерами. Он позволяет на лету тестировать HTTP-запросы и мгновенно замечать ошибки, которые могли бы проявиться только в реальном использовании. С его помощью вы можете быть спокойны за корректность работы вашего API ещё до деплоя в продакшн.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ