Что такое внедрение зависимостей (Dependency Injection) и как это используется в тестировании?

«Что такое внедрение зависимостей (Dependency Injection) и как это используется в тестировании?» — вопрос из категории Архитектура, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Внедрение зависимостей (DI) — это архитектурный паттерн, при котором компонент получает свои зависимости (например, сервисы, репозитории, клиенты API) извне, а не создает их внутри себя. Для QA это критически важно, так как DI является основой для изоляции тестируемого модуля и подмены реальных зависимостей на заглушки (mocks/stubs).

Проблема без DI (сложное тестирование):

// Код тесно связан с конкретной реализацией. Невозможно протестировать EmailService отдельно от реального SMTP-сервера.
public class NotificationService {
    private EmailSender emailSender = new RealEmailSender(); // Зависимость создается внутри

    public void sendWelcome(User user) {
        emailSender.send(user.getEmail(), "Welcome!");
    }
}

Решение с DI (простое тестирование):

// Зависимость внедряется через конструктор.
public class NotificationService {
    private final EmailSender emailSender;

    public NotificationService(EmailSender emailSender) { // DI через конструктор
        this.emailSender = emailSender;
    }

    public void sendWelcome(User user) {
        emailSender.send(user.getEmail(), "Welcome!");
    }
}

Как это используется в тестах (на примере Mockito для Java):

@Test
void sendWelcome_ShouldCallEmailSender() {
    // 1. Создаем mock-зависимость
    EmailSender mockEmailSender = Mockito.mock(EmailSender.class);

    // 2. Внедряем mock в тестируемый сервис
    NotificationService service = new NotificationService(mockEmailSender);
    User testUser = new User("test@example.com");

    // 3. Выполняем действие
    service.sendWelcome(testUser);

    // 4. Проверяем, что метод был вызван с правильными аргументами
    Mockito.verify(mockEmailSender).send("test@example.com", "Welcome!");
}

Преимущества для тестирования:

  • Изоляция: Можно тестировать бизнес-логику NotificationService, не беспокоясь о работе реального EmailSender.
  • Контроль: Mock-объекты позволяют эмулировать любые сценарии (успех, ошибка, таймаут).
  • Скорость: Тесты выполняются мгновенно, так как не требуют сетевых вызовов или доступа к БД.