-
Notifications
You must be signed in to change notification settings - Fork 433
Description
I'm implementing consumer-driven contract testing with Spring Cloud Contract (SCC) on a Spring Boot provider service. I've identified a gap in the standard verification approach: SCC only validates that fields declared in the contract are present in the provider response. It does not detect provider DTO fields that consumers have silently dropped from their contracts.
The Problem
Consider this contract lifecycle:
// v1: Consumer contract expects "dateTime"
response {
body(
id: "123",
dateTime: "2025-01-15T10:30:00Z",
clientId: "cid-123"
)
}
// v2: Consumer removes "dateTime" — no longer needed
response {
body(
id: "123",
clientId: "cid-123"
)
}
After dateTime is removed from the contract:
- SCC regenerates provider tests,
dateTimeis no longer asserted - The provider DTO still declares
dateTime - The regenerated test passes silently
- The provider continues serializing
dateTimein every response - The discrepancy goes undetected
This silently accumulates technical debt:
- Dead DTO fields: Provider maintains fields no consumer uses
- False confidence: All tests pass, DTO and contract are out of sync
My Current Approach
I implemented a supplementary ContractFieldVerificationTest that runs alongside the standard SCC-generated tests. It:
- Parses SCC-generated test source files to extract asserted fields (using regex patterns targeting various
assertThatJson()styles) - Reflects on provider DTO class hierarchies to collect all non-static instance fields
- Compares bidirectionally:
- Dead code: fields in DTO but absent from contract assertions
- Missing implementation: fields in contract assertions but absent from DTO
Example failure output:
DEAD CODE: 1 field(s) in DTO but not in contract:
- dateTime
ACTION REQUIRED: Remove from ResponseDTO.java or add back to the consumer contract
The test file content is cached via @BeforeAll to avoid redundant I/O, and the contracts directory is resolved dynamically to be resilient to consumer version changes.
The Concern
A teammate has raised that parsing generated test source files as a verification signal is a clumsy approach, coupling test verification to generated code internals that could change with any SCC version upgrade.
Question
Is there an established, idiomatic approach for bidirectional contract-DTO synchronization in Spring Cloud Contract that avoids parsing generated sources?
Specifically:
- Does SCC offer a strict body-matching mode that would fail if the provider returns fields not declared in the contract (similar to Pact's PactVerifyProvider with strict matching)?
- Is there a StubRunnerExtension hook or a custom ContractVerifierConfigurer that could intercept response serialization for this purpose?
- Would switching to Pact be more appropriate here, given its richer support for explicit field-level matching rules?
- Alternatively, is there a pattern using Jackson @JsonIgnoreProperties(allowGetters=false) or a custom serialization filter that could enforce DTO-contract alignment at the framework level rather than at the test level?
Any guidance on the idiomatic approach, or confirmation that source-parsing is an acceptable trade-off, would be appreciated!