Вопрос 25 · Раздел 17

Как тестировать микросервисы

Structured Java interview answer with junior, middle, and senior-level explanation.

Версии по языкам: English Russian Ukrainian

🟢 Junior Level

Три уровня тестирования:

  1. Unit тесты — тестирование одного класса/метода
  2. Integration тесты — тестирование взаимодействия с БД, внешними сервисами
  3. Contract тесты — проверка совместимости API между сервисами
// Unit тест
@Test
void testOrderCalculation() {
    OrderService service = new OrderService();
    Order order = service.createOrder(List.of(item1, item2));
    assertEquals(100, order.total());
}

🟡 Middle Level

Integration тесты

@SpringBootTest
@Testcontainers
class OrderServiceIntegrationTest {
    
    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");
    
    @Test
    void testCreateOrder() {
        Order order = orderService.createOrder(request);
        assertNotNull(order.getId());
    }
}

Contract тесты (Pact)

@Provider("Order Service")
@Consumer("User Service")
public class OrderServiceContractTest {
    @TestTemplate
    void testGetUserOrders(PactVerificationContext context) {
        // Interaction = один запрос-ответ между consumer и provider.
        // Pact проверяет, что provider может обработать запрос, который ожидает consumer.
        // Contract тест ловит breaking changes в API до попадания в production.
        context.verifyInteraction();
    }
}

Типичные ошибки

  1. Тесты с реальными сервисами:
    Сетевой вызов → реальный Payment Service → медленно (100-500ms на запрос)
    и нестабильно (сеть может упасть, сервис может быть недоступен).
    Решение: mock или testcontainers
    

🔴 Senior Level

Test pyramid

     /  E2E    \      — мало (10%)
    / Integration \   — средне (20%)
   /    Unit       \  — много (70%)

Consumer-driven contracts

User Service (consumer) определяет контракт → Order Service (provider) проверяет

Production Experience

Testcontainers:

@Testcontainers
class UserRepositoryTest {
    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");

    // @DynamicPropertySource (Spring Boot 2.2.6+) — динамически передаёт порты
    // контейнера в Spring Environment до инициализации контекста.
    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
    }
}

Best Practices

✅ Test pyramid
✅ Testcontainers для интеграции
✅ Contract тесты для API
✅ Mock внешних сервисов
✅ CI/CD pipeline с тестами

❌ Только E2E тесты
❌ Тесты с реальными сервисами
❌ Без contract тестов

🎯 Шпаргалка для интервью

Обязательно знать:

  • Test pyramid: Unit (70%) → Integration (20%) → E2E (10%)
  • Unit тесты — один класс/метод, быстро, изолированно
  • Integration тесты — взаимодействие с БД, внешними сервисами (Testcontainers)
  • Contract тесты (Pact) — проверка совместимости API между сервисами, ловят breaking changes
  • Testcontainers — Docker-контейнеры для интеграционных тестов (PostgreSQL, Kafka)
  • Consumer-driven contracts: consumer определяет контракт, provider проверяет
  • Mock внешних сервисов — не тестировать с реальными (медленно, нестабильно)

Частые уточняющие вопросы:

  • Зачем contract тесты? Ловят breaking changes в API до попадания в production — consumer ожидает X, provider должен отдать X.
  • Testcontainers vs mock? Testcontainers = реальный сервис в Docker (надёжнее), mock = заглушка (быстрее).
  • Почему не только E2E? E2E медленно, хрупкие, сложно дебажить. Unit быстрее, стабильнее.
  • @DynamicPropertySource что делает? Динамически передаёт порты контейнера в Spring Environment до инициализации контекста.

Красные флаги (НЕ говорить):

  • “Только E2E тесты достаточно” — нет, медленно, хрупкие, сложно дебажить
  • “Тесты с реальными Payment Service” — нет, медленно (100-500ms) и нестабильно
  • “Contract тесты не нужны, есть Swagger” — Swagger описывает API, contract тесты проверяют совместимость
  • “Unit тесты = интеграционные” — нет, unit = один класс, integration = взаимодействие

Связанные темы:

  • [[26. Какие инструменты используются для оркестрации микросервисов]]
  • [[15. Как организовать коммуникацию между микросервисами]]
  • [[22. Что такое distributed tracing]]
  • [[9. Что такое API Gateway и какие задачи он решает]]
  • [[17. Как обеспечить отказоустойчивость микросервисов]]