Test Data for Contract Testing: One Entity Definition, Every Service
Test data for contract testing tends to fail in a specific, boring way: service A's tests define "customer 42" with one set of fields, service B's tests define its own "customer 42" with slightly different ones, and a contract test fails not because either service actually broke a contract, but because the two hand-maintained fixture copies of the same entity quietly drifted apart. The fix isn't a smarter mock — it's making sure every service that needs a customer, an order, or a subscription is pulling that entity from the same definition instead of retyping it.
This is a different failure mode from the one in mock API response data, which covers a single team feeding the same generated payload into MSW, Storybook, and Playwright. That's one team, one repo, multiple tools. This post is about many teams, many repos, many CI pipelines, all needing the same entity — and the cost being cut here is cross-team coordination and the time spent debugging integration breaks that turn out to be nothing but a fixture mismatch, not the per-edit effort of maintaining any one fixture file.
What is "test data for contract testing," specifically?
A contract test — whether it's a Pact interaction, a Spring Cloud Contract stub, or a hand-rolled schema check — verifies that a consumer's expectation of a response and a provider's actual response agree on shape and, often, on specific field values. The test data is the payload sitting inside that check: the customer object a consumer expects back, the order object a provider promises to return. JsonFabrica doesn't run or manage that check. It generates the JSON payload that goes into it — the actual verification is still Pact's job, or whichever contract testing tool you're already using.
Why does microservices test data drift across repos?
Each service typically owns its own repo, its own CI pipeline, and its
own fixtures directory. When a customer entity shows up in three
services — say, an accounts service that owns it, an orders service that
references it, and a billing service that reads it — it's common for
each repo to have its own hand-typed JSON blob representing "a customer"
for testing purposes. Nobody wires these together on purpose; it happens
because copying a plausible-looking object into a new repo is the fastest
way to get a test passing. Then the accounts team adds a status field,
updates their own fixture, and has no reason to know the orders team's
copy exists, let alone go fix it. Months later a consumer-driven contract
test fails, and the postmortem is "our fixture didn't have status,"
not an actual contract violation.
One entity definition, every service
The alternative isn't smarter fixtures — it's fewer of them. Instead of
each service hand-maintaining its own copy of a customer shape, one
JsonFabrica template defines what a customer looks like, once, and every
service's test setup calls the same template generation
API to get one:
curl -s -X POST https://api.jsonfabrica.com/v1/templates/tpl_customer/generate \
-H 'Authorization: Bearer sk_...' \
-H 'content-type: application/json' \
-d '{"seed": 42}'
Every service that runs this call with seed: 42 gets back the
byte-identical customer record — same name, same email, same id shape —
regardless of which repo, which CI runner, or which team's test suite is
calling it. That's the core of shared test fixtures across services: not
a file copied into N repos, but N repos calling the same source and
getting the same answer.
Consumer-driven contract test data across related entities
Contracts rarely cover a single flat entity. A provider's response to "get this customer's orders" needs a customer and a set of orders that actually reference that customer, and if the consumer side and provider side of a Pact interaction each stub that relationship independently, they can each be internally consistent and still disagree with each other. A relational batch generation API call generates both sides together, with the child's field wired to the parent's output:
{
"seed": 42,
"documents": [
{ "templateId": "tpl_customer", "alias": "customer", "count": 1 },
{
"templateId": "tpl_order",
"alias": "order",
"count": 3,
"relations": { "customerId": { "from": "customer.id", "strategy": "round-robin" } }
}
]
}
With seed fixed, that call returns the same customer and the same
three orders every time it's run — from any service's test setup. A
consumer team writing a Pact interaction and a provider team writing the
matching provider state handler can both generate from this exact batch
definition and know their fixtures describe the same underlying data,
which is what Pact test data actually needs to hold up: not that the
JSON is realistic, but that both sides of the interaction agree on it.
For how the relations map keeps ids like customerId pointing at a
customer that actually exists in the same batch, see Random Isn't
Realistic; for
why fixed seeds alone aren't enough to keep IDs stable and
collision-free across separate runs, see Unique Test Data
Generation.
Does this replace Pact or Spring Cloud Contract?
No, and it's worth being direct about that. JsonFabrica has no Pact broker integration. It doesn't publish consumer expectations, doesn't verify a provider against a pact file, and doesn't diff what a consumer expects against what a provider actually returns — that's the entire job of Pact, Spring Cloud Contract, or whatever contract testing tool a team already runs. JsonFabrica sits one layer below that: it's the data source those tools' setup code calls to get a customer, an order, or whatever entity the contract is about. It returns JSON over HTTP, full stop — it doesn't insert anything into a database, and it isn't a plugin or fixture library built into Pact, Postman, or any specific test framework.
Do teams still have to update templates by hand when a contract changes?
Yes. When a provider adds a field to a response, or a consumer starts expecting a new one, someone edits the JsonFabrica template by hand, exactly the same action as editing a static fixture file — JsonFabrica doesn't watch an OpenAPI spec or a pact file and regenerate templates on its own. On pure per-edit effort, this is a wash, not a win. The actual advantage is narrower and more honest: it's one template edit, made once, that every service consuming that entity picks up the next time it calls the API — instead of N separately-typed fixture files across N repos, each needing its own fix, with no guarantee anyone remembers to touch all of them. That's a reduction in cross-team coordination and in the time spent debugging contract failures that turn out to be fixture drift, not a reduction in how much typing any single edit takes.
FAQ
What is test data for contract testing? It's the sample request and response payloads that consumer and provider tests use to verify a contract, such as a customer or order object referenced by both a consumer's expectation and a provider's verification test. Contract testing tools like Pact and Spring Cloud Contract check that these payloads match between the two sides; they don't generate the payloads themselves.
Does JsonFabrica integrate with Pact or a Pact broker? No. JsonFabrica has no Pact broker integration and doesn't publish, verify, or diff contracts or pacts. It generates the JSON data you can use inside a Pact interaction or a provider state setup, over a plain HTTP API, but the actual contract verification is still done by Pact or whichever contract-testing tool your team uses.
How do multiple microservices share the same test data without copying fixtures? Each service points its test setup at the same JsonFabrica template and, for related entities, the same relational batch definition, instead of each repo keeping its own hand-typed JSON fixture for the same entity. Every service calls the generation API and gets an identically-shaped record back, so a customer used in one service's contract test is defined the same way as the customer used in another service's test.
Does this replace consumer-driven contract testing tools like Pact? No. JsonFabrica is a data source, not a contract verification tool. It returns JSON over HTTP; it doesn't publish consumer expectations, verify a provider against them, or manage a pact broker. You'd still run Pact, Spring Cloud Contract, or a similar tool to actually check that consumer and provider agree — JsonFabrica just supplies the data those checks run against.
Do teams still have to update test data by hand when a contract or schema changes? Yes. JsonFabrica doesn't watch an OpenAPI spec or a Pact contract and regenerate templates automatically; when a field is added or renamed, someone edits the JsonFabrica template the same way they'd edit a fixture file. What changes is that it's one template edit shared by every service using that entity, instead of each service's copy needing its own separate fix.
Can JsonFabrica insert generated test data directly into a service's database? No. JsonFabrica returns JSON over HTTP from a template or batch generation call; it doesn't connect to or insert into any database, and it isn't a plugin or fixture library for a specific test framework. Each service's test setup is responsible for taking that JSON and doing whatever it needs to with it, whether that's a Pact interaction, a provider state handler, or a direct API call.
If your services keep failing contract tests over fixture drift rather than actual contract breaks, the fix isn't better fixtures — it's fewer of them. Define each entity once as a JsonFabrica template and let every service's contract test setup call the same batch generation API for it.
Generate realistic test data with JsonFabrica
Describe the shape of your data once, then generate as many fresh, realistic JSON documents as you need via a simple API call.