Уявімо, що ми створюємо мікросервіс, який відповідає за обробку замовлень в онлайн-магазині. Він обробляє HTTP-запити, викликає сервіси для перевірки наявності товарів на складі, взаємодіє з базою даних для збереження інформації про замовлення. Усе це — набір взаємодіючих компонентів. І навіть якщо ви протестували їх окремо юніт-тестами, це ще не гарантує, що все працює разом як треба. Саме тут вступає в гру інтеграційне тестування.
Інтеграційне тестування на рівні мікросервісу дозволяє:
- Перевірити взаємодію між контролерами, сервісами, репозиторіями та іншими компонентами.
- Переконатися, що весь мікросервіс функціонує коректно, не використовуючи реальні зовнішні залежності.
- Емулювати реальні HTTP-запити й перевірити, як застосунок їх обробляє, повертаючи відповіді.
MockMvc: ключовий інструмент для інтеграційного тестування
Перш ніж братися за тестування, давайте розберемося, що таке MockMvc.
MockMvc — це зручний інструмент із Spring Test, який дозволяє:
- Моделювати HTTP-запити до вашого застосунку без запуску реального web-сервера.
- Перевіряти, як ваш контролер обробляє запити, повертає відповіді і працює з внутрішніми сервісами.
- Симулювати реальні сценарії роботи API, включно з відправкою параметрів, тіла запиту, налаштувань заголовків і багато іншого.
Уявіть собі так: замість того, щоб збирати всю машину повністю і ганяти її по тестовому треку, ви тестуєте лише її двигун, але під навантаженням, наближеним до реального. Простими словами: 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 ще до деплою в продакшн.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ