Consumer-Driven Contract Testing
debt(d7/e5/b5/t5)
Closest to 'only careful code review or runtime testing' (d7). While tools like Pact and pact-php exist to automate contract verification, the absence of contract testing itself (using E2E tests as the only verification method) is only detectable through careful review of the test strategy or when breaking changes manifest in staging/production. The detection_hints indicate the code pattern is 'E2E tests as only way to verify API compatibility' — this gap isn't flagged by any automated tool.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix indicates writing Pact consumer tests for each dependency, which requires creating new test files, setting up a Pact broker, and modifying provider CI pipelines. This is a significant setup effort spanning test infrastructure and CI configuration, but contained within the testing layer rather than requiring architectural changes.
Closest to 'persistent productivity tax' (b5). Contract testing applies to web/api contexts and is tagged as microservices/api infrastructure. Once adopted, it creates an ongoing tax: every API change requires contract updates, consumer teams must maintain their expectations, and the Pact broker becomes part of the deployment workflow. However, it's scoped to service boundaries rather than defining the entire system's shape.
Closest to 'notable trap' (t5). The misconception field explicitly states developers wrongly believe 'contract testing replaces integration testing.' This is a documented gotcha that most developers working with microservices eventually learn — contracts verify compatibility, not business logic flow. Additionally, common_mistakes show traps like providers writing contracts instead of consumers, which contradicts the fundamental 'consumer-driven' premise.
Also Known As
TL;DR
Explanation
In microservices, integration tests require both services running simultaneously — slow, fragile, and hard to maintain. Consumer-Driven Contract Testing (CDC) with Pact solves this: the consumer writes tests defining what request/response it expects, generating a contract (pact file). The provider then runs its own verification against the contract without needing the consumer running. Both can deploy independently once the contract is satisfied.
Diagram
sequenceDiagram
participant CONS as Consumer
participant BROKER as Pact Broker
participant PROV as Provider
CONS->>CONS: Write consumer test<br/>define expected request/response
CONS->>BROKER: Publish contract pact file
Note over CONS,BROKER: Consumer CI passes
PROV->>BROKER: Fetch contract
PROV->>PROV: Verify provider meets contract
PROV-->>BROKER: Verification result
BROKER-->>CONS: Can I deploy? yes/no
Common Misconception
Why It Matters
Common Mistakes
- Provider teams writing contracts rather than consumers — the whole point is the consumer defines what it needs.
- Not publishing contracts to a broker (Pact Broker) — contracts stored locally cannot be verified by the provider CI.
- Contracts that are too strict — specifying exact response body structure breaks on innocuous additions.
- Not running contract verification in the provider's CI — contracts only help if the provider actually checks them.
Code Examples
// No contract testing — provider changes break consumer silently:
// Provider team renames 'user_id' to 'id' in response
// Consumer code: $response['user_id'] — now null
// Discovered in production, not in CI
// Both teams deployed independently with no coordination
// Consumer defines contract (Pact PHP):
$builder->uponReceiving('a request for user 42')
->with(['method' => 'GET', 'path' => '/users/42'])
->willRespondWith([
'status' => 200,
'body' => ['user_id' => 42, 'name' => Matchers::like('Alice')]
]);
// Pact file published to broker
// Provider CI verifies: GET /users/42 returns user_id (not id)