Why Synthetic Test Data Beats Hand-Written Fixtures
Every API project accumulates a pile of hand-written JSON fixture files. They start small — a handful of sample users, a couple of orders — and they're easy to reason about at first. Then the schema changes, a new required field shows up, and half the fixtures silently go stale until a test fails in a way nobody can explain at a glance.
The problem with hand-written fixtures
Static fixtures have three recurring failure modes:
- They drift from the real schema. Nothing forces a fixture file to track a TypeScript interface or an OpenAPI schema, so it's easy for a field to be renamed in code but not in the fixture.
- They're not diverse enough. A handful of copy-pasted sample users rarely exercises edge cases like unicode names, boundary numbers, or empty arrays.
- They leak real-looking PII. Fixtures copied from a production export (even "anonymized" ones) have a way of carrying real names, emails, or addresses into version control.
What synthetic data generation fixes
A synthetic data generator like JsonFabrica flips the model: instead of
committing static JSON, you commit a template — a JSON document with
function placeholders like <getRandomEmail()> or
<getRandomFullName()> — and generate fresh, realistic documents from it
on demand.
{
"id": "<getUuid()>",
"name": "<getRandomFullName()>",
"email": "<getRandomEmail()>",
"signupDate": "<getRandomDate('2024-01-01', '2026-01-01')>"
}
That template is the source of truth. When the schema changes, you edit the template once, not every fixture file scattered across a test suite.
Reproducibility still matters
Randomness is only useful in tests if it's controllable. JsonFabrica
supports a seed on generation calls, so a "random" document is exactly
reproducible across CI runs — you get fresh-looking data without flaky,
non-deterministic assertions.
Relations, not just flat objects
Real APIs rarely deal in isolated objects — an order references a
customer, a comment references a post. JsonFabrica's batch generation
supports exactly that: generate a customer and a set of orders in one
call, with the orders' customerId fields wired to the generated
customer automatically.
Getting started
If you're tired of maintaining brittle fixture files, the Getting Started guide walks through your first template and API call in a few minutes, and the Examples page has worked templates for common shapes — single documents, relational batches, and reproducible seeded runs.