Prompt
How do I set up contract testing between services?
Latest observation
Contract testing is a way to verify that two services agree on the shape and behavior of the API they share, without needing full end-to-end tests for every scenario.
The basic idea
There are two sides:
- Consumer: the service that calls an API
- Provider: the service that exposes that API
A contract test checks that:
- the consumer’s expectations are valid
- the provider actually fulfills those expectations
The most common approach is consumer-driven contract testing.
Typical setup
1. Define the interactions the consumer needs
In the consumer service, write tests that describe:
- request method/path/headers/body
- expected response status
- expected response body shape and values
Example:
GET /users/123- response
200 - body includes
id,name,email
2. Publish the contract
The consumer test generates a contract artifact, often JSON.
This contract is then shared with the provider via:
- a contract broker such as Pact Broker
- a CI artifact store
- another shared registry
3. Verify the provider against the contract
In the provider service, run verification tests that replay the contract interactions against the real API implementation.
If the provider matches the contract, the test passes.
4. Automate in CI/CD
A common flow:
- Consumer tests run on PRs and publish contracts
- Provider CI pulls latest contracts and verifies them
- Deployment is blocked if verification fails
Popular tools
Pact
The most common consumer-driven contract testing tool.
- Works for HTTP and message-based systems
- Supports many languages
- Uses a broker for sharing contracts and tracking compatibility
Spring Cloud Contract
Good for JVM/Spring ecosystems.
- Generates stubs and tests
- Strong fit if you’re already on Spring
Other options
- OpenAPI / Swagger for schema-based validation
- gRPC Protobuf compatibility checks
- AsyncAPI for event/message contracts
Recommended workflow with Pact
Consumer side
- Write a test using Pact.
- Stub the provider response for local development.
- Generate and publish the contract.
Provider side
- Fetch contracts from the broker.
- Run provider verification against your API.
- Publish verification results back to the broker.
Broker usage
The broker helps answer:
- Which consumers depend on this provider?
- Is this provider version safe to deploy?
- Has every consumer contract been verified?
Example process
Suppose OrderService calls CustomerService.
Consumer test in OrderService
It expects:
GET /customers/42- response
200 - JSON:
{ "id": 42, "name": "Ava" }
Provider verification in CustomerService
CustomerService runs tests against its own API and confirms it returns the expected shape and fields.
If CustomerService changes name to fullName, the contract test fails before deployment.
Good practices
- Test behavior, not implementation
- Focus on what the consumer needs, not all fields the provider happens to return.
- Keep contracts small
- One test per meaningful interaction.
- Version and publish contracts automatically
- Don’t manage them manually if you can avoid it.
- Use a broker
- Especially when many services are involved.
- Still keep some integration tests
- Contract tests don’t replace all end-to-end tests.
Common pitfalls
- Over-specifying responses
- If the consumer checks fields it doesn’t really use, you make the provider too rigid.
- Testing too many scenarios in one contract
- Keep each interaction focused.
- Treating contract tests as unit tests
- They’re about service boundaries.
- Skipping CI automation
- Contract testing is most valuable when enforced on every change.
When to use contract testing
It’s especially useful when:
- many teams own different services
- APIs change frequently
- you want to reduce brittle end-to-end tests
- you have HTTP, messaging, or event-driven integration points
If you want, I can also show:
- a Pact example in JavaScript, Java, or Python, or
- a recommended CI pipeline for contract testing.