Project Brief — Test Strategy for an Order Management Microservices System

11 min read

You have spent six chapters learning every layer of microservices testing — component tests with WireMock and Testcontainers, consumer-driven contracts with Pact, integration tests with Docker Compose, resilience testing with Toxiproxy, observability assertions, Kafka consumer tests, eventual consistency patterns, and saga compensation. This capstone brings every technique together into a single, realistic system. Your job is not to read and move on — it is to design and build a complete test strategy for a production-grade order management platform, then implement the most critical pieces from scratch.

The system you are testing

The platform consists of six services communicating over HTTP and Kafka, each with its own PostgreSQL database:

User Service — registration, login, JWT issuance, profile management. All other services call it to resolve user identity.

Product Service — product catalog, inventory tracking, stock reservation. Exposes /products/{id} and /products/{id}/reserve.

Order Service — the system's orchestrator. Handles cart, checkout, and the full order lifecycle (PENDING → CONFIRMED → SHIPPED → DELIVERED). Calls User Service and Product Service synchronously. Publishes order.created, order.cancelled, and order.refund_requested events to Kafka.

Payment Service — processes charges and refunds. Called synchronously by Order Service during checkout. Publishes payment.succeeded and payment.failed to Kafka.

Notification Service — listens for Kafka events and sends email and SMS. Non-critical: a Notification Service failure must not affect order processing.

Reporting Service — consumes events from all services and materialises aggregated views. Reads are eventually consistent; reports may lag by up to 30 seconds.

Order Management System
  • – Component tests
  • – Pact provider
  • – Component tests
  • – Pact provider
  • – Component + contract tests
  • – Integration tests
  • – Saga tests
  • – Chaos + circuit breaker
  • – Pact provider
  • Kafka consumer tests –
  • Non-critical path tests –
  • Eventual consistency tests –
  • E2E report assertions –

Your deliverables

Work through these in order — each builds on the last.

1. Test strategy document

Before writing a single test, write a one-page strategy that answers: how many tests of each type for each service? For the Order Service (the orchestrator), your pyramid should be heavily weighted toward component and contract tests, with a small integration suite and only 3–5 E2E tests covering the most critical user journeys. For stateless services like Notification, unit tests plus a Kafka consumer test may be sufficient.

Explicitly call out which flows are covered at each level. "Place order" should appear at the component level (Order Service tests with WireMock), the integration level (real services + Kafka), and the E2E level (Playwright from browser to confirmation page). "Send notification email" only appears at the Kafka consumer test level — not in E2E.

2. Component test suite for Order Service

Implement a full @SpringBootTest class with:

  • PostgreSQLContainer for Order Service's own database
  • WireMockServer stubs for User Service, Product Service, and Payment Service
  • KafkaContainer to verify that order.created is published when an order succeeds
  • At minimum: happy-path create, out-of-stock path, payment failure path, order cancellation

Use @DynamicPropertySource to wire all containers into the Spring context. Use dynamicPort() for all WireMock servers.

3. Pact contract tests

Write consumer tests from Order Service's perspective against User Service and Product Service. For each:

  • Define the interaction using LambdaDsl matchers, not hardcoded values
  • Publish the generated pact to your local Pact Broker (or a file-based broker for local dev)
  • Write the provider verification tests on the User Service and Product Service side
  • Run can-i-deploy as a CI gate before any service deployment

4. Docker Compose integration environment

Write docker-compose.test.yml that starts all six services, a Kafka broker, and six PostgreSQL instances. Every service must declare a healthcheck and all depends_on must use condition: service_healthy. The environment must be fully self-contained — no external calls, no shared staging databases.

5. Integration tests for critical flows

Using ComposeContainer, write two integration tests:

  • Place order: POST a checkout request, poll until order status is CONFIRMED, verify inventory was decremented on Product Service, verify order.created was published to Kafka
  • Refund: request a refund on a delivered order, verify Payment Service processed it, verify order.refund_requested was published

6. Saga tests

Order placement is a saga: reserve inventory → charge payment → confirm order. If payment fails, inventory must be released. Test three scenarios:

  • Happy path: all steps succeed, order reaches CONFIRMED
  • Payment failure: payment returns 402, verify inventory is released and order reaches CANCELLED
  • Notification failure: Notification Service is down, verify order still reaches CONFIRMED (non-critical dependency)

7. Chaos test — circuit breaker on Payment Service

Using Toxiproxy, inject 3-second latency into the connection between Order Service and Payment Service. Configure Order Service's circuit breaker with a 1-second timeout and 3-call threshold. Submit four rapid checkout requests and assert:

  • First three fail with 503 Service Unavailable (circuit breaker trips after timeout)
  • Fourth fails immediately (circuit is OPEN — no attempt to Payment Service)
  • Remove the toxic, wait for the half-open window, submit one more request — circuit closes

8. Five E2E tests (Playwright)

Cover these journeys and only these:

  1. Register → browse → add to cart → checkout → confirm order
  2. Login → view order history → request refund → verify refund status
  3. Admin: view real-time order report (verifies Reporting Service)
  4. Browse out-of-stock product → attempt checkout → receive clear error
  5. Failed payment → retry with different card → confirm order

9. Distributed tracing assertions

Add a test that places an order, extracts the X-Request-ID from the response header, queries Jaeger's API for that trace, and asserts that spans exist for all four synchronous service calls (Order → User, Order → Product, Order → Payment, Order → self for DB write).

10. CI/CD pipeline

Write a GitHub Actions workflow with four jobs:

  • fast-tests: component tests + Pact tests, runs on every PR, target < 3 minutes
  • integration-tests: Docker Compose suite, runs on every PR, target < 10 minutes
  • chaos-tests: Toxiproxy resilience suite, scheduled weekly
  • e2e-tests: Playwright suite, scheduled nightly

Every job that deploys a service must call can-i-deploy before promoting to the next environment.

⚠️ Common mistakes

  • Skipping the strategy document and jumping straight to code. The strategy document forces you to decide what is worth testing at each level before you are three days into writing component tests for Notification Service (which barely needs any). The document is not busywork — it is the map that stops you spending a week in the wrong place.
  • Making Notification Service critical in your test setup. Notification Service is explicitly non-critical. If your Docker Compose integration tests fail because the Notification Service container crashes, you've encoded a false dependency. Tests that verify non-critical services should use separate failure scenarios, not block the critical path suite.
  • Testing every service at every layer. The Reporting Service has no synchronous callers and no saga participation. It needs: a Kafka consumer test, an eventual consistency test, and one E2E test that reads a report. It does not need component tests with WireMock — there is nothing to stub. Apply the pyramid proportionally per service.

🎯 Practice task

Before moving to the walkthrough, spend 45 minutes on this planning step:

  1. Draw the system. Sketch the six services on paper — boxes for services, arrows for synchronous HTTP calls, dashed arrows for Kafka events. Label each arrow with the endpoint or event name.
  2. Annotate test types. Next to each service box, write which test types apply: component, contract (consumer? provider? both?), integration, chaos, E2E. The Order Service should have all five. The Notification Service should have two.
  3. Count your tests. For the Order Service specifically, estimate: how many component tests? How many Pact consumer interactions? How many integration test scenarios? How many E2E tests? A reasonable starting target: 15–20 component tests, 6–8 Pact interactions, 3–4 integration scenarios, 2 E2E tests.
  4. Identify the riskiest integration. Which service-to-service call, if it broke silently, would cause the most business harm? That is where you invest your contract tests first and your chaos engineering second.
  5. Write your strategy document. One page, bullet points, per-service breakdown. Keep it — you will need it to self-assess in Lesson 3.

// tip to track lessons you complete and pick up where you left off across devices.