JavaRush /Курси /Модуль 5. Spring /Лекція 264: Інтеграційне тестування мікросервісів з MockM...

Лекція 264: Інтеграційне тестування мікросервісів з MockMvc

Модуль 5. Spring
Рівень 21 , Лекція 3
Відкрита

Уявімо, що ми створюємо мікросервіс, який відповідає за обробку замовлень в онлайн-магазині. Він обробляє 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));
    }
}

У нас є два методи:

  1. GET /books/{id} — повертає книгу за її ідентифікатором.
  2. 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")); // Перевіряємо автора
    }
}

Що тут відбувається?

  1. Анотації:
    • @SpringBootTest піднімає весь контекст Spring.
    • @AutoConfigureMockMvc налаштовує MockMvc автоматично.
    • @MockBean створює мок для залежності BookService, який ми будемо використовувати для ізоляції.
  2. Тести:
    • У testGetBook ми мокуємо метод findBookById в сервісі, щоб він повертав об'єкт Book. Потім відправляємо GET-запит і перевіряємо, що відповідь містить правильні дані.
    • У testCreateBook ми мокуємо метод saveBook, відправляємо POST-запит з JSON-даними і перевіряємо, що відповідь містить дані створеної книги.
  3. MockMvc API:
    • mockMvc.perform(...) виконує HTTP-запит.
    • andExpect(...) містить всі перевірки результату, від статусу відповіді до вмісту JSON.

Типові помилки при використанні MockMvc

Отже, на що варто звернути увагу:

  • Не оголошено залежність MockMvc або @AutoConfigureMockMvc. У такому випадку тести не зможуть використовувати MockMvc.
  • Помилки серіалізації JSON. Перевірте, чи підключений Jackson до вашого проєкту.
  • Відсутність моків для залежностей. MockMvc тестує тільки контролер, тому обов'язково мокайте сервіси через @MockBean.

MockMvc — неймовірно потужний інструмент для тестування взаємодії з вашими контролерами. Він дозволяє на ходу тестувати HTTP-запити і миттєво помічати помилки, які могли б проявитися тільки в реальному використанні. За його допомогою ви можете бути спокійні за коректність роботи вашого API ще до деплою в продакшн.

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