Как принципы SOLID связаны с тестированием?

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

Ответ

Да, соблюдение принципов SOLID напрямую улучшает тестируемость кода, делая тесты проще в написании и поддержке.

Влияние каждого принципа:

  1. Single Responsibility (SRP) — Класс с одной ответственностью имеет меньше причин для изменения и требует меньше тестов, которые фокусируются на одной функциональности.
  2. Open/Closed (OCP) — Код, открытый для расширения, позволяет добавлять новые тесты для новых поведений, не затрагивая и не переписывая существующие тесты для старого кода.
  3. Liskov Substitution (LSP) — Возможность подстановки подтипов гарантирует, что тесты, написанные для базового класса или интерфейса, будут корректно работать с любым производным классом.
  4. Interface Segregation (ISP) — Узкие, специфичные интерфейсы упрощают создание моков (mock objects) и стабов (stubs) для тестирования, так как не требуется реализовывать неиспользуемые методы.
  5. Dependency Inversion (DIP) — Зависимость от абстракций (интерфейсов), а не от конкретных реализаций, позволяет легко внедрять тестовые двойники (mocks, stubs) в модуль.

Практический пример (DIP + тестирование):

// Интерфейс - абстракция
public interface PaymentGateway {
    boolean charge(double amount);
}

// Сервис зависит от абстракции
public class OrderService {
    private final PaymentGateway paymentGateway;

    public OrderService(PaymentGateway paymentGateway) {
        this.paymentGateway = paymentGateway; // Внедрение зависимости
    }

    public boolean processOrder(Order order) {
        return paymentGateway.charge(order.getAmount());
    }
}

// Юнит-тест с использованием Mock-объекта
@Test
void processOrder_ShouldReturnTrue_WhenPaymentSucceeds() {
    // 1. Arrange (Подготовка)
    PaymentGateway mockGateway = mock(PaymentGateway.class);
    when(mockGateway.charge(100.0)).thenReturn(true);

    OrderService service = new OrderService(mockGateway);
    Order testOrder = new Order(100.0);

    // 2. Act (Действие)
    boolean result = service.processOrder(testOrder);

    // 3. Assert (Проверка)
    assertTrue(result);
    verify(mockGateway).charge(100.0); // Проверка взаимодействия
}

Таким образом, SOLID — это основа для создания модульного, поддерживаемого и легко тестируемого кода.