В чем разница в подходах к тестированию монолитных и микросервисных приложений?

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

Ответ

Архитектура приложения напрямую влияет на стратегию тестирования. Основные различия:

Аспект Монолит Микросервисы
Основной тип тестов Модульные (Unit) и интеграционные (Integration) Контрактные (Contract), компонентные (Component), E2E
Сложность изоляции Низкая (все в одном процессе) Высокая (распределенная система, внешние зависимости)
Фокус тестирования Корректность работы компонентов внутри приложения Корректность взаимодействия между сервисами и их независимое развертывание

Пример для монолита (интеграционный тест):

@SpringBootTest
class UserServiceIntegrationTest {
    @Autowired
    private UserService userService;
    @Autowired
    private UserRepository repository;

    @Test
    void createUser_savesToDatabase() {
        User user = userService.createUser("Alex");
        assertThat(repository.findById(user.getId())).isPresent();
    }
}

Пример для микросервисов (тест с моком внешнего сервиса):

@Test
void placeOrder_callsPaymentService() {
    // 1. Мокаем клиент внешнего Payment Service
    PaymentServiceClient mockClient = mock(PaymentServiceClient.class);
    when(mockClient.charge(any())).thenReturn(new PaymentResponse(Status.SUCCESS));

    // 2. Тестируем наш сервис в изоляции
    OrderService orderService = new OrderService(mockClient);
    OrderResult result = orderService.placeOrder(new Order());

    // 3. Проверяем взаимодействие
    assertThat(result.isSuccess()).isTrue();
    verify(mockClient).charge(any()); // Проверка вызова
}

В микросервисной архитектуре критически важны контрактные тесты (например, с Pact), чтобы гарантировать, что изменения в одном сервисе не сломают его потребителей.