Інтеграційні тести перевіряють взаємодію різних компонентів додатка (наприклад, контролерів, сервісів і репозиторіїв) і їх коректну роботу під єдиною конфігурацією. Вони дозволяють переконатися, що компоненти додатка «розуміють» один одного і працюють в унісон. На відміну від Unit-тестів, інтеграційні тести можуть використовувати реальні бази даних, веб-сервери та інші живі залежності.
Чому інтеграційні тести важливі?
- Перевірка цілісності додатка: інтеграційні тести перевіряють, що всі компоненти додатка працюють разом без збоїв.
- Реальне оточення: ці тести близькі до реальних умов роботи додатка, включно з взаємодією з базою даних, сервісами та API.
- Виявлення помилок взаємодії: навіть якщо окремі компоненти працюють коректно, їх взаємодія може містити помилки, які виявляють інтеграційні тести.
Різниця між 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: вказує використовувати певний профіль конфігурації.
Основні помилки при написанні інтеграційних тестів
- Надмірне навантаження на контекст: використовувати
@SpringBootTestскрізь підряд. Якщо потрібно протестувати лише шар REST або репозиторії, краще використовувати вузькоспеціалізовані анотації (@WebMvcTest,@DataJpaTest). - Відсутність тестової бази даних: використовуйте in-memory бази або Testcontainers, щоб не забруднювати реальну базу.
- Неізольовані тести: завжди намагайтеся робити тести незалежними один від одного, щоб їх порядок виконання не впливав на результат.
Інтеграційні тести — це ключовий інструмент для того, щоб ваш додаток працював правильно як єдине ціле. Опановуючи їх, ви почуватиметеся впевнено, знаючи, що ваш код не розвалиться після кожної нової зміни.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ