Marco Rossi·
Pact consumer test that breaks the provider build the moment they rename a response field
Implement consumer-driven contract tests between microservices using Pact or similar tools to prevent breaking API changes.
Contract Testing with Pact / Consumer-Driven
You are a microservices testing architect specializing in contract testing. Implement consumer-driven contract tests for the following service interactions.
**Consumer Service:**
{{consumer_service}}
**Provider Service:**
{{provider_service}}
**API Interactions:**
{{api_interactions}}
**Tech Stack:**
{{tech_stack}}
**Contract Testing Tool:**
{{contract_tool}}
**CI/CD Platform:**
{{cicd_platform}}
Generate:
1. **Consumer Contract Tests**: Pact consumer tests defining expected interactions:
- Request matchers (flexible matching rules)
- Response body matchers with type and regex constraints
- Provider state setup for each interaction
- Error response contracts (4xx, 5xx)
2. **Provider Verification Tests**: Pact provider verification setup:
- State management handlers
- Provider-side test data setup
- Verification against published contracts
3. **Pact Broker Configuration**: Contract publishing and verification workflow
4. **CI Integration Pipeline**:
- Consumer: publish contracts on build
- Provider: verify contracts before deployment
- Can-I-Deploy gate checking
5. **Bi-Directional Contracts**: OpenAPI spec as provider contract if applicable
6. **Breaking Change Detection**: Automated detection of contract modifications
7. **Version Strategy**: Contract versioning aligned with service versioning
8. **Webhook Setup**: Automatic provider verification trigger on contract change
9. **Failure Diagnostics**: How to debug contract test failures
10. **Team Workflow**: Development workflow preventing breaking changes
Output complete test implementations and CI configuration.
Ergebnisse
Consumer-driven contract test between a `web-bff` consumer and an `orders-api` provider using Pact (JS). Prevents the provider from shipping a breaking response shape.
```typescript
// consumer: web-bff/test/orders.pact.test.ts
import { PactV3, MatchersV3 } from "@pact-foundation/pact";
const { like, eachLike, regex } = MatchersV3;
const provider = new PactV3({ consumer: "web-bff", provider: "orders-api" });
describe("orders-api contract", () => {
it("returns an order by id", async () => {
provider
.given("an order 42 exists") // provider state
.uponReceiving("a request for order 42")
.withRequest({ method: "GET", path: "/orders/42" })
.willRespondWith({
status: 200,
body: {
id: like("42"),
status: regex("pending|shipped|cancelled", "pending"),
totalCents: like(4198),
items: eachLike({ sku: like("SKU-004521"), qty: like(1) }),
},
});
await provider.executeTest(async (mock) => {
const res = await fetch(`${mock.url}/orders/42`);
expect(res.status).toBe(200);
});
});
});
```
The matchers (`like`, `regex`, `eachLike`) assert on *type and shape*, not exact values — so the contract stays robust to data changes but breaks the moment the provider drops a field or changes a type.
**Provider side** replays the published pact against `orders-api`, using a state handler that seeds "an order 42 exists" before the verification request. **CI flow:** consumer publishes the contract to the Pact Broker on build; the provider's pipeline runs verification and a `can-i-deploy` gate blocks its release if the contract isn't satisfied. **Result:** a provider engineer who renames `totalCents → total` gets a red build before it ever reaches the consumer.
Modell: Claude Sonnet 4
8 Likes2 SavesScore: 5