Contract Testing Workflow with Pact
Have the consumer write a pact for the expected interactions, publish it to a broker, and let the provider verify against the pact so a breaking change fails the provider build.
Objective
Catch breaking changes between a consumer and a provider before they reach production by verifying the provider against the consumer pact on every change.
Environment
- A consumer with a pact test suite
- A provider with a pact verification step
- A pact broker reachable from both CI pipelines
Steps
1. Consumer writes the pact
In the consumer test suite, declare the interactions the consumer expects from the provider and generate the pact file.
Expected state: A pact JSON file that lists the requests the consumer makes and the responses it expects.
2. Publish to the broker
On every consumer CI build, publish the pact to the broker tagged with the consumer version.
Expected state: The broker holds the latest pact for the consumer version, ready for the provider to verify.
3. Provider verifies
On every provider CI build, pull the pact from the broker and run the provider against it, failing the build on a mismatch.
Expected state: A provider change that breaks the consumer pact fails the provider build before it ships.
4. Deploy on can-i-deploy
Before deploying either side, run can-i-deploy against the broker to confirm the versions are compatible.
Expected state: A deploy is blocked if the consumer and provider versions have not been verified as compatible.
Decision points
Who writes the pact?
- The consumer team
- The provider team
The consumer writes the pact, because the consumer knows what it needs; the provider verifies.
When do we verify?
- On every provider build
- On a schedule
On every provider build, so a breaking change fails before merge, not after a nightly run.
Expected outcome
A breaking change fails the provider build, and a deploy is blocked unless the consumer and provider versions are verified compatible.
Verification
Confirm the provider build fails on a pact mismatch, can-i-deploy blocks an incompatible deploy, and the broker shows a verified matrix.
Cleanup
Archive old pact versions on a retention policy, and tag the broker with the production version so rollbacks verify against the right pact.
The consumer owns the contract
The consumer knows what it needs, so it writes the pact. The provider verifies against it. A provider change that breaks the consumer expectation fails the provider build, not the consumer’s.
new Interaction()
.uponReceiving('a request for a user')
.withRequest({ method: 'GET', path: '/users/1' })
.willRespondWith({ status: 200, body: { id: 1 } });
Publish and verify
The consumer CI publishes the pact to the broker. The provider CI pulls it and verifies. The broker is the meeting point; neither side talks to the other directly.
pact-broker can-i-deploy --pacticipant consumer --version $VERSION
Deploy only when compatible
Before either side deploys, run can-i-deploy. It blocks the deploy if the versions have not been verified as compatible. Tag the broker with the production version so a rollback verifies against the right pact.
Verification
A breaking change fails the provider build, can-i-deploy blocks an incompatible deploy, and the broker shows a verified matrix. Verify on every provider build, not on a schedule, so the failure lands before merge.