Чем функциональное тестирование отличается от интеграционного?

«Чем функциональное тестирование отличается от интеграционного?» — вопрос из категории Тестирование, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Функциональное тестирование проверяет корректность работы отдельного модуля, класса или метода в изоляции, согласно его техническим требованиям. Интеграционное тестирование проверяет взаимодействие и совместную работу нескольких модулей, систем или с внешними зависимостями (БД, API).

Критерий Функциональное тестирование Интеграционное тестирование
Объект Один модуль/юнит Группа модулей, система, внешние сервисы
Изоляция Зависимости заменяются заглушками (mocks/stubs) Используются реальные или приближенные к реальным зависимости
Скорость Быстрое Медленное (из-за внешних вызовов, БД)
Цель Проверить внутреннюю логику Проверить корректность взаимодействия и контракты

Пример функционального (юнит) теста (JUnit + Mockito):

@Test
void calculateDiscount_ShouldApplyDiscount() {
    // Arrange: Создаем изолированный объект и заглушку
    PriceService mockPriceService = mock(PriceService.class);
    when(mockPriceService.getBasePrice(any())).thenReturn(100.0);
    OrderService service = new OrderService(mockPriceService);

    // Act
    double finalPrice = service.calculateFinalPrice("item123", 10);

    // Assert
    assertEquals(90.0, finalPrice); // Проверяем чистую логику
}

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

@SpringBootTest
@AutoConfigureMockMvc
class OrderIntegrationTest {
    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private OrderRepository repository; // Реальный репозиторий с тестовой БД

    @Test
    void createOrder_ShouldPersistInDb() throws Exception {
        // Act & Assert: Проверяем цепочку HTTP -> Сервис -> БД
        mockMvc.perform(post("/api/order")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{ "item": "book" }"))
                .andExpect(status().isOk());

        // Проверяем интеграцию с БД
        assertFalse(repository.findAll().isEmpty());
    }
}