В чем разница между unit-тестами и интеграционными тестами?

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

Ответ

Unit-тесты проверяют изолированно одну единицу кода (класс, метод). Интеграционные тесты проверяют взаимодействие нескольких модулей или с внешними системами.

Сравнительная таблица:

Характеристика Unit-тест Интеграционный тест
Объект тестирования Один класс/метод (единица). Группа классов, модуль, взаимодействие с БД, API.
Зависимости Изолируются с помощью моков (Mockito). Используются реальные или приближённые к реальным зависимости (testcontainers, in-memory БД).
Скорость Очень быстрые (миллисекунды). Медленные (секунды, минуты).
Цель Проверить корректность логики единицы кода. Проверить корректность взаимодействия и интеграции компонентов.
Частота запуска Запускаются постоянно, при каждом изменении кода. Запускаются реже (ночью, перед релизом).

Пример Unit-теста (JUnit 5 + Mockito):

@Test
void shouldReturnUserWhenFound() {
    // 1. ARRANGE: Создаём мок зависимости и тестируемый сервис
    UserRepository mockRepo = mock(UserRepository.class);
    UserService service = new UserService(mockRepo);
    User expectedUser = new User(1L, "Alice");
    when(mockRepo.findById(1L)).thenReturn(Optional.of(expectedUser));

    // 2. ACT: Вызываем тестируемый метод
    User actualUser = service.getUserById(1L);

    // 3. ASSERT: Проверяем результат
    assertEquals("Alice", actualUser.getName());
    verify(mockRepo).findById(1L); // Проверяем взаимодействие с моком
}

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

@SpringBootTest
@AutoConfigureTestDatabase // Заменяет БД на embedded (H2)
class UserServiceIntegrationTest {
    @Autowired
    private UserRepository repository; // Реальный репозиторий
    @Autowired
    private UserService service; // Реальный сервис

    @Test
    void shouldSaveAndRetrieveUser() {
        // Действия с реальной БД
        User savedUser = repository.save(new User(null, "Bob"));
        User foundUser = service.getUserById(savedUser.getId());

        assertThat(foundUser.getName()).isEqualTo("Bob");
    }
}

Пирамида тестирования: Unit-тесты составляют её основу (их больше всего), а интеграционные находятся уровнем выше (их меньше). Оба типа необходимы для качественного проекта.