Question 25 · Section 17

How to test microservices

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

Language versions: English Russian Ukrainian

🟢 Junior Level

Three levels of testing:

  1. Unit tests — testing a single class/method
  2. Integration tests — testing interaction with DB, external services
  3. Contract tests — verifying API compatibility between services
// Unit test
@Test
void testOrderCalculation() {
    OrderService service = new OrderService();
    Order order = service.createOrder(List.of(item1, item2));
    assertEquals(100, order.total());
}

🟡 Middle Level

Integration tests

@SpringBootTest
@Testcontainers
class OrderServiceIntegrationTest {

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

    @Test
    void testCreateOrder() {
        Order order = orderService.createOrder(request);
        assertNotNull(order.getId());
    }
}

Contract tests (Pact)

@Provider("Order Service")
@Consumer("User Service")
public class OrderServiceContractTest {
    @TestTemplate
    void testGetUserOrders(PactVerificationContext context) {
        // Interaction = a single request-response between consumer and provider.
        // Pact verifies that the provider can handle the request the consumer expects.
        // Contract tests catch breaking changes in API before they reach production.
        context.verifyInteraction();
    }
}

Common mistakes

  1. Tests with real services:
    Network call → real Payment Service → slow (100-500ms per request)
    and unstable (network can fail, service can be unavailable).
    Solution: mock or testcontainers
    

🔴 Senior Level

Test pyramid

     /  E2E    \      — few (10%)
    / Integration \   — medium (20%)
   /    Unit       \  — many (70%)

Consumer-driven contracts

User Service (consumer) defines contract → Order Service (provider) verifies

Production Experience

Testcontainers:

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

    // @DynamicPropertySource (Spring Boot 2.2.6+) — dynamically passes container
    // ports to Spring Environment before context initialization.
    @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 for integration
✅ Contract tests for API
✅ Mock external services
✅ CI/CD pipeline with tests

❌ Only E2E tests
❌ Tests with real services
❌ Without contract tests

🎯 Interview Cheat Sheet

Must know:

  • Test pyramid: Unit (70%) → Integration (20%) → E2E (10%)
  • Unit tests — single class/method, fast, isolated
  • Integration tests — interaction with DB, external services (Testcontainers)
  • Contract tests (Pact) — verify API compatibility between services, catch breaking changes
  • Testcontainers — Docker containers for integration tests (PostgreSQL, Kafka)
  • Consumer-driven contracts: consumer defines contract, provider verifies
  • Mock external services — do not test with real ones (slow, unstable)

Frequent follow-up questions:

  • Why contract tests? Catch breaking changes in API before production — consumer expects X, provider must deliver X.
  • Testcontainers vs mock? Testcontainers = real service in Docker (more reliable), mock = stub (faster).
  • Why not only E2E? E2E is slow, fragile, hard to debug. Unit tests are faster, more stable.
  • What does @DynamicPropertySource do? Dynamically passes container ports to Spring Environment before context initialization.

Red flags (NOT to say):

  • “Only E2E tests are enough” — no, slow, fragile, hard to debug
  • “Tests with real Payment Service” — no, slow (100-500ms) and unstable
  • “Contract tests are not needed, we have Swagger” — Swagger describes API, contract tests verify compatibility
  • “Unit tests = integration tests” — no, unit = single class, integration = interaction

Related topics:

  • [[26. What tools are used for microservices orchestration]]
  • [[15. How to organize communication between microservices]]
  • [[22. What is distributed tracing]]
  • [[9. What is API Gateway and what problems does it solve]]
  • [[17. How to ensure fault tolerance of microservices]]