ESC
Type to search guides, tutorials, and reference documentation.
Verified by Garnet Grid

Contract Testing for Microservices

Implement consumer-driven contract testing to prevent breaking changes across microservices. Covers Pact, Spring Cloud Contract, schema evolution, and CI/CD integration patterns.

Contract testing solves the fundamental problem of microservice integration: how do you know that changing Service A won’t break Service B, C, and D? Integration tests are slow and brittle. Contract tests are fast, isolated, and catch breaking changes before they reach production.


Why Contract Testing Exists

Without contracts:
    Service A changes response format
        → Deploys successfully (its own tests pass)
            → Service B starts failing (unexpected field type)
                → Service C crashes (missing required field)
                    → Incident at 2 AM

With contracts:
    Service A changes response format
        → Contract test fails in CI
            → PR blocked
                → Developer fixes compatibility
                    → Safe deploy

Consumer-Driven vs Provider-Driven

ApproachWho Defines the ContractBest For
Consumer-drivenConsumers define what they needInternal microservices
Provider-drivenProvider publishes its schemaPublic APIs, third-party integrations
Bi-directionalBoth sides verify against a shared specOpenAPI-first development

Consumer-Driven Contract Testing (Pact)

1. Consumer writes a test:
   "When I call GET /users/123, I expect { id: 123, name: string, email: string }"

2. Pact generates a contract file (JSON):
   { interactions: [{ request: ..., response: ... }] }

3. Contract published to Pact Broker

4. Provider verification:
   Provider replays the contract interactions against its actual API
   If any interaction fails → Provider knows it would break the consumer

Tooling Comparison

ToolLanguage SupportContract FormatBrokerBest For
Pact12+ languagesPact JSONPact Broker / PactflowMulti-language ecosystems
Spring Cloud ContractJava/KotlinGroovy DSL / YAMLN/A (CI artifact)Spring ecosystem
SpecmaticJVMOpenAPI specN/AOpenAPI-first teams
DreddAny (HTTP)API Blueprint / OpenAPIN/AAPI documentation testing

Schema Evolution Rules

Change TypeSafe?Contract Impact
Add optional field to response✅ YesExisting consumers ignore it
Add required field to response⚠️ DependsSafe if consumers use tolerant readers
Remove field from response❌ NoBreaks consumers that depend on it
Change field type❌ NoBreaks deserialization
Add optional field to request✅ YesExisting requests still valid
Add required field to request❌ NoBreaks existing consumers
Rename field❌ NoBreaks serialization on both sides
Add new endpoint✅ YesNo existing consumer affected
Remove endpoint❌ NoBreaks any consumer calling it

Pact Workflow in Detail

Consumer Side

Test: "User service client"
    Given: User 123 exists
    When: GET /users/123
    Then: Response contains:
        - status: 200
        - body: { id: integer, name: string, email: string }
        - headers: { Content-Type: "application/json" }

→ Generates: user-service-consumer-user-service-provider.json
→ Published to Pact Broker

Provider Side

Verification:
    Load contract from Pact Broker
    For each interaction:
        Set up provider state ("User 123 exists")
        Replay request (GET /users/123)
        Compare actual response against contract expectations
        Report: PASS or FAIL with diff

Pact Broker

FeaturePurpose
Contract storageCentral repository for all contracts
Verification statusTrack which provider versions verified which contracts
Can-I-DeployBinary check: “Is it safe to deploy this version?”
WebhooksTrigger provider verification when new contracts are published
Network diagramVisualize service dependencies automatically

Integration with CI/CD

Consumer PR:
    → Unit tests
    → Contract tests (generate Pact file)
    → Publish contract to Pact Broker
    → Trigger provider verification (webhook)
    → can-i-deploy check
    → Merge

Provider PR:
    → Unit tests
    → Verify all consumer contracts from Pact Broker
    → can-i-deploy check
    → Merge
    → Deploy

Testing Async / Event-Driven Contracts

PatternHow to Test
Message queuesPact supports message-based contracts
Event schemasUse Avro/Protobuf schema registry as contract source
WebhooksConsumer defines expected webhook payload format
GraphQLContract on query/mutation shapes and response structures

Anti-Patterns

Anti-PatternProblemFix
Testing every fieldContracts become brittle, break on any changeTest only fields the consumer actually uses
No Pact BrokerContracts shared via git = stale contractsUse Pact Broker for real-time contract management
Provider state ignoredTests fail because test data doesn’t matchImplement provider state handlers for each scenario
Testing internal microservices like public APIsOver-specification, slow evolutionConsumer-driven contracts allow flexibility
No can-i-deploy gateContracts exist but aren’t enforcedAdd can-i-deploy as a CI gate before merge

Checklist

  • Contract testing approach chosen (consumer-driven for internal, provider-driven for external)
  • Pact Broker (or equivalent) deployed and accessible from CI
  • Every consumer has contract tests for each provider it calls
  • Provider verification runs on every provider PR
  • can-i-deploy gate enforced before merge to main
  • Async/event contracts tested (message pacts or schema registry)
  • Schema evolution rules documented and enforced
  • Network diagram generated from Pact Broker and reviewed quarterly

:::note[Source] This guide is derived from operational intelligence at Garnet Grid Consulting. For microservices architecture consulting, visit garnetgrid.com. :::

Jakub Dimitri Rezayev
Jakub Dimitri Rezayev
Founder & Chief Architect • Garnet Grid Consulting

Jakub holds an M.S. in Customer Intelligence & Analytics and a B.S. in Finance & Computer Science from Pace University. With deep expertise spanning D365 F&O, Azure, Power BI, and AI/ML systems, he architects enterprise solutions that bridge legacy systems and modern technology — and has led multi-million dollar ERP implementations for Fortune 500 supply chains.

View Full Profile →