Как тестировать микросервисы
Structured Java interview answer with junior, middle, and senior-level explanation.
🟢 Junior Level
Три уровня тестирования:
- Unit тесты — тестирование одного класса/метода
- Integration тесты — тестирование взаимодействия с БД, внешними сервисами
- 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();
}
}
Типичные ошибки
- Тесты с реальными сервисами:
Сетевой вызов → реальный 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. Как обеспечить отказоустойчивость микросервисов]]