Что такое интеграционное тестирование (Integration Testing)?

Ответ

Интеграционное тестирование — это уровень тестирования, который проверяет корректность взаимодействия и совместной работы двух или более интегрированных модулей, компонентов или систем.

Цель: выявить дефекты на стыках компонентов, такие как:

  • Несовместимость интерфейсов (API, схемы данных).
  • Некорректная передача данных или состояния.
  • Ошибки в бизнес-логике, возникающие при интеграции.
  • Проблемы с внешними зависимостями (БД, кэш, message brokers).

Пример интеграционного теста (Spring Boot + JUnit):

@SpringBootTest
class OrderServiceIntegrationTest {
    @Autowired
    private OrderService orderService;
    @Autowired
    private PaymentServiceClient paymentServiceClient;
    @MockBean
    private NotificationService notificationService; // Мокаем внешний сервис

    @Test
    void processOrder_ShouldSucceed_WhenPaymentIsApproved() {
        // Arrange: Настраиваем мок и тестовые данные
        when(paymentServiceClient.charge(any())).thenReturn(PaymentStatus.APPROVED);
        Order testOrder = new Order("order-123", 100.0);

        // Act: Вызываем метод, который интегрирует несколько сервисов
        OrderResult result = orderService.processOrder(testOrder);

        // Assert: Проверяем результат и взаимодействие
        assertThat(result.isSuccess()).isTrue();
        verify(paymentServiceClient).charge(any()); // Проверяем вызов интеграции
        verify(notificationService).sendOrderConfirmation(any()); // Проверяем side-effect
    }
}
Ключевые отличия от unit-тестов: Аспект Unit-тестирование Интеграционное тестирование
Объект Один класс/функция Группа классов, модули, внешние системы
Зависимости Изолируются (мокаются) Используются реальные или приближенные к реальным
Скорость Быстрое Медленное (требует поднятия контекста, БД и т.д.)
Цель Проверить логику в изоляции Проверить корректность взаимодействия

Ответ 18+ 🔞

Давай я тебе сейчас, как есть, без прикрас, про интеграционное тестирование разложу. Это ж не просто так, хуй с горы, а целая философия, блядь.

Представь, ты собрал движок от танка, трансмиссию и пушку по отдельности. Unit-тесты — это когда ты каждый узел на стенде крутишь и смотришь: вал вращается? Пружина пружинит? Отлично. А потом ты это всё в корпус засовываешь, кнопку «ВПЕРЁД» жмёшь, а танк, сука, разворачивается нахуй и начинает стрелять себе в хобот. Вот это и есть момент, для которого интеграционные тесты придумали, ёпта. Чтобы выявить, где один модуль другому в сраку даёт, когда они начинают вместе работать.

Суть, блядь, в чём: проверить не внутренности, а стыки. Эти ваши интерфейсы, которые обещали одно, а на деле передают пиздец какой. Или данные, которые из базы вылезли кривыми, и вся логика посыпалась. Или внешний сервис, который в ответ на запрос вместо «ок» присылает тебе «иди нахуй, сервер сгорел».

Смотри, вот тебе живой пример, чтоб не быть пиздаболом. Допустим, у нас сервис заказов и внешняя платёжка.

@SpringBootTest // Вот тут уже всё по-взрослому, поднимается полконтекста, не unit
class OrderServiceIntegrationTest {
    @Autowired
    private OrderService orderService; // Реальный сервис, не мок!
    @Autowired
    private PaymentServiceClient paymentServiceClient; // Клиент к реальной (или тестовой) платёжке
    @MockBean
    private NotificationService notificationService; // А вот это мокаем, потому что ебаться с реальной рассылкой в тестах — терпения ноль ебать

    @Test
    void processOrder_ShouldSucceed_WhenPaymentIsApproved() {
        // Подготовка: говорим моку платёжки, чтобы он не реальный запрос слал, а сразу «одобрено» возвращал
        when(paymentServiceClient.charge(any())).thenReturn(PaymentStatus.APPROVED);
        Order testOrder = new Order("order-123", 100.0);

        // Действие: запускаем всю эту махину взаимодействия
        OrderResult result = orderService.processOrder(testOrder);

        // Проверка: а сработало ли всё как задумано?
        assertThat(result.isSuccess()).isTrue(); // Заказ прошёл?
        verify(paymentServiceClient).charge(any()); // Платёжку вообще дернули?
        verify(notificationService).sendOrderConfirmation(any()); // И письмецо клиенту попытались отправить?
    }
}

Видишь разницу? Это не изолированная проверка формулы. Это проверка цепочки: «заказ -> вызов платёжки -> обработка её ответа -> попытка нотификации». Если где-то в этой цепочке ебучка — тест её выловит.

А чтобы совсем уж вротберунчик не было, вот тебе табличка, где всё как на духу:

Чё проверяем Unit-тесты (быстрые, изолированные) Интеграционные тесты (медленные, честные)
Объект обстрела Один класс, одна функция. Один солдат на стрельбище. Группа классов, модули, внешние системы. Взвод в полевых условиях.
Зависимости Все изолируются (мокаются, стабаются). Никого рядом нет. Используются реальные или максимально близкие к бою. База, кэш, внешние API.
Скорость Быстро, как укол. Сотни в секунду. Медленно, блядь. Поднять контекст, базу, сети — это не хуй собачий.
Главная цель Убедиться, что солдат умеет стрелять в идеальных условиях. Убедиться, что взвод не перестреляет друг друга при совместной работе.

Короче, интеграционное тестирование — это когда ты перестаёшь верить на слово, что всё «должно работать», и начинаешь проверять, как оно реально соединяется и ебётся между собой. Без этого — чистая рулетка, волнение ебать.