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

Лекція 136: Інтеграційні тести з використанням Spring Boot Test

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

Інтеграційні тести перевіряють взаємодію різних компонентів додатка (наприклад, контролерів, сервісів і репозиторіїв) і їх коректну роботу під єдиною конфігурацією. Вони дозволяють переконатися, що компоненти додатка «розуміють» один одного і працюють в унісон. На відміну від Unit-тестів, інтеграційні тести можуть використовувати реальні бази даних, веб-сервери та інші живі залежності.

Чому інтеграційні тести важливі?

  1. Перевірка цілісності додатка: інтеграційні тести перевіряють, що всі компоненти додатка працюють разом без збоїв.
  2. Реальне оточення: ці тести близькі до реальних умов роботи додатка, включно з взаємодією з базою даних, сервісами та API.
  3. Виявлення помилок взаємодії: навіть якщо окремі компоненти працюють коректно, їх взаємодія може містити помилки, які виявляють інтеграційні тести.

Різниця між Unit та інтеграційними тестами

Характеристика Unit-тест Інтеграційний тест
Мета Тестування окремого методу Тестування взаємодії компонентів
Оточення Ізольоване, з моками Справжнє оточення
Використовувані дані Заглушки (mocked data) Реальна або тестова база даних
Продуктивність Дуже швидкі Повільніші
Область застосування Локальна перевірка логіки Перевірка цілісної функціональності

Навіщо використовувати Spring Boot Test?

Spring Boot надає весь необхідний інструментарій для написання як Unit, так і інтеграційних тестів. Головна «суперсила» в інтеграційному тестуванні тут — анотація @SpringBootTest. Вона запускає весь контекст Spring, дозволяючи тестувати додаток у умовах, максимально наближених до реальних.

Переваги використання Spring Boot Test:

  • Автоматичне завантаження контексту додатка.
  • Підключення тестової бази даних через конфігурацію.
  • Зручність у тестуванні REST API, взаємодії компонентів і бази даних.
  • Гнучкість для тестування певних частин додатка, якщо використовується фільтрація контексту.

Анотація @SpringBootTest

Для написання інтеграційних тестів у Spring Boot ми використовуємо анотацію @SpringBootTest. Вона дозволяє завантажити повний контекст додатка, включаючи контролери, сервіси, репозиторії, конфігурації і навіть вбудований веб-сервер (якщо потрібно).

Ось мінімальний приклад тестового класу:


@SpringBootTest
class IntegrationTestExample {

    @Autowired
    private SomeService someService;

    @Test
    void testServiceMethod() {
        String result = someService.performAction();
        assertEquals("Expected Result", result);
    }
}

Важливі моменти:

  • При використанні @SpringBootTest весь контекст додатка завантажується, що робить тести повільнішими за Unit-тести. Тому використовуйте їх тільки там, де це реально необхідно.
  • Якщо хочете протестувати лише частину контексту, можна обмежити завантажуваний контекст, наприклад, за допомогою @WebMvcTest або @DataJpaTest.

Конфігурація тестового оточення

Інколи інтеграційні тести вимагають використання тимчасової бази даних або інших компонентів, що не впливатимуть на реальне оточення. Spring Boot спрощує цей процес.

1. Використання in-memory бази даних

Для тестування репозиторіїв можна використовувати H2 — базу даних в пам'яті:


# application-test.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

Потім у тестах ми вказуємо Spring використовувати цей тестовий профіль:


@SpringBootTest
@ActiveProfiles("test")  // Вказує на використання application-test.properties
class RepositoryIntegrationTest {
    // Тести
}

2. Автоматичне підчищення даних

Для тестів з базою даних корисно автоматично очищати дані після виконання кожного тесту. Spring Boot робить це за допомогою анотації @Transactional:


@SpringBootTest
@Transactional  // Відкат всіх змін після кожного тесту
class DatabaseIntegrationTest {
    // Тести
}

3. MockMVC і тестування REST API

Щоб перевірити взаємодію з REST API, використовується MockMVC, який дозволяє імітувати HTTP-запити і аналізувати відповіді.


Написання інтеграційного тесту: Практичний приклад

Припустимо, у нас є додаток для управління задачами. Ми протестуємо REST API, який взаємодіє з базою даних для створення і отримання задач.

1. Приклад коду контролера


@RestController
@RequestMapping("/api/tasks")
public class TaskController {

    @Autowired
    private TaskService taskService;

    @PostMapping
    public ResponseEntity<Task> createTask(@RequestBody Task task) {
        return ResponseEntity.status(HttpStatus.CREATED).body(taskService.createTask(task));
    }

    @GetMapping("/{id}")
    public ResponseEntity<Task> getTask(@PathVariable Long id) {
        return ResponseEntity.ok(taskService.getTaskById(id));
    }
}

2. Сервіс і репозиторій


@Service
public class TaskService {

    @Autowired
    private TaskRepository taskRepository;

    public Task createTask(Task task) {
        return taskRepository.save(task);
    }

    public Task getTaskById(Long id) {
        return taskRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Task not found"));
    }
}

public interface TaskRepository extends JpaRepository<Task, Long> {}

3. Тестування API через MockMvc


@SpringBootTest
@AutoConfigureMockMvc
class TaskControllerIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void testCreateAndRetrieveTask() throws Exception {
        // JSON для створення задачі
        String newTaskJson = "{ \"title\": \"Learn Testing\", \"description\": \"Understand integration tests\" }";

        // Створюємо задачу
        MvcResult result = mockMvc.perform(post("/api/tasks")
                .contentType(MediaType.APPLICATION_JSON)
                .content(newTaskJson))
                .andExpect(status().isCreated())
                .andReturn();

        // Отримуємо ID створеної задачі
        Long taskId = JsonPath.read(result.getResponse().getContentAsString(), "$.id");

        // Перевіряємо, що задача існує
        mockMvc.perform(get("/api/tasks/" + taskId))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.title").value("Learn Testing"))
                .andExpect(jsonPath("$.description").value("Understand integration tests"));
    }
}

Корисні анотації для інтеграційних тестів

  • @SpringBootTest: запускає повний контекст додатка.
  • @AutoConfigureMockMvc: автоматично підключає MockMvc для тестування REST API.
  • @Transactional: забезпечує відкат змін у базі даних після виконання тесту.
  • @TestPropertySource: вказує окремі файли властивостей для тестів.
  • @ActiveProfiles: вказує використовувати певний профіль конфігурації.

Основні помилки при написанні інтеграційних тестів

  1. Надмірне навантаження на контекст: використовувати @SpringBootTest скрізь підряд. Якщо потрібно протестувати лише шар REST або репозиторії, краще використовувати вузькоспеціалізовані анотації (@WebMvcTest, @DataJpaTest).
  2. Відсутність тестової бази даних: використовуйте in-memory бази або Testcontainers, щоб не забруднювати реальну базу.
  3. Неізольовані тести: завжди намагайтеся робити тести незалежними один від одного, щоб їх порядок виконання не впливав на результат.

Інтеграційні тести — це ключовий інструмент для того, щоб ваш додаток працював правильно як єдине ціле. Опановуючи їх, ви почуватиметеся впевнено, знаючи, що ваш код не розвалиться після кожної нової зміни.

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