Q25 of 37 · API testing

How would you architect an API test suite from scratch for a microservices team?

API testingSeniorapimicroservicesarchitecturecontract-testingsenior

Short answer

Short answer: Layer the strategy: per-service unit + integration tests owned by service teams, cross-service contract tests (Pact), a thin layer of E2E covering business-critical journeys. Standardise tooling, fixtures, auth, and CI patterns. Each service tests its own contract; the platform team owns the orchestration and the journey-level coverage.

Detail

Microservices testing fails when one team tries to test everything end-to-end. The right architecture distributes responsibility — each service owns its own contracts; the platform layer owns the journeys.

The four-layer model:

Layer 1 — Per-service tests (owned by each service team):

  • Unit tests for handlers and business logic.
  • Integration tests against a real database, hitting the service via HTTP.
  • Schema validation against the service's OpenAPI / GraphQL schema.
  • Stay fast; run in the service's own CI on every commit.

Layer 2 — Contract tests (cross-service):

  • Consumer-driven with Pact, or provider-driven with OpenAPI as the contract.
  • Each consumer publishes its expectations; each provider verifies them in CI.
  • This catches the bulk of cross-service breakage without running multi-service environments.

Layer 3 — Selective E2E (owned by platform / QA platform):

  • 10-30 tests covering business-critical journeys: signup → onboard → buy.
  • Run against a real staging environment with all services up.
  • Optimised for "is the platform healthy?" not for line-level coverage.
  • Run on merge to main or before deploy, not on every PR.

Layer 4 — Synthetic monitors (production):

  • Subset of L3 journeys running every 5 minutes against prod.
  • Page on failure; backstop the test pyramid.

Standardisation that's worth it:

  • Tooling — pick one HTTP test library per language, one schema validator, one mock server. Fragmentation across services kills shared learning.
  • Auth helper — every test needs to issue a token. One library; every service uses it.
  • Test data — a shared "create test user / org / tenant" helper across services.
  • CI patterns — same Jenkinsfile / GitHub Actions template for unit-build-contract-test, parameterised by service.
  • Reporting — Allure or equivalent, aggregated across services.

What to avoid:

  • One mega E2E suite that tests every service's flow end-to-end. Breaks when any service is down; nobody owns; flake destroys trust.
  • Running other services' integration tests in your CI. Service boundaries should match test boundaries.
  • Custom auth in each service's test setup. Inconsistent token expiry, scopes, and error handling.

The platform team's job: maintain the standards, the shared tooling, and the L3/L4 journeys. Service teams own everything else. Without this division, either everything centralises (bottleneck) or nothing centralises (chaos).

Migration if you inherit a mess:

  1. Inventory existing tests by layer. Which are unit, which are E2E, which are duplicates?
  2. Adopt one shared library (auth, fixtures) and migrate services one at a time.
  3. Stand up Pact or OpenAPI contract verification for the most-coupled service pair.
  4. Trim E2E down to journeys, not "every endpoint of every service."
  5. Document the layered model and run a workshop with service owners.

The interview signal: thinking about who owns what, not just "what tests exist." Microservices testing is a distributed-responsibility problem first, a tooling problem second.

// WHAT INTERVIEWERS LOOK FOR

Layered model with explicit ownership, contract tests as the cross-service layer, E2E reserved for journeys, and the discipline of standardising tooling without centralising authorship.

// COMMON PITFALL

Treating microservices like a monolith with multiple URLs and writing one big E2E suite. The result is unowned, slow, brittle — and gets gradually ignored until it provides no signal.