Document Workflow

Generate test fixtures without copying production data

Define a fixture schema, generate bounded numbers and labeled strings, add deliberate boundary cases, and validate exact JSON or CSV without copying production records.

Written and tested by Published: Reviewed:

How this workflow was checked

For the Random Data Workbench review, we preserved the source shown in “Build a shareable order-import fixture” and completed “Remove production values instead of mutating them” and “Export and validate the exact destination format”. The produced output was compared literally where possible, with “Anonymizing a production export in place” and “Treating random valid values as full coverage” checked against the linked failure evidence.

The fixture contained ten schema-valid synthetic orders plus isolated boundary rows for quantity, price, uniqueness, missing UUID, length, and CSV quoting failures, with no production record reused.

Problem

Copying a production row into a test, support ticket, demo, or screenshot can expose personal data and secrets. Replacing every field with short placeholders is safer but can hide failures caused by realistic lengths, decimal steps, uniqueness constraints, Unicode, CSV quoting, and JSON numeric types. Purely random fixtures create a third problem: they change on every run and rarely exercise exact boundaries. A useful fixture set must preserve the documented schema, contain no production values, separate representative valid samples from deliberate invalid cases, and remain stable wherever assertions depend on exact output.

When to use this

  • A bug report needs a shareable JSON or CSV reproduction without customer, tenant, order, or account data.
  • An import pipeline needs realistic valid rows plus explicit empty, duplicate, malformed, minimum, and maximum cases.
  • A demo or screenshot needs readable labels that cannot be mistaken for real accounts or credentials.
  • A test suite currently generates fresh random data and exact assertions are intermittently failing.

Steps

  1. Step 1

    Write down the target schema before generating anything

    List each field name, data type, nullability, minimum and maximum, decimal scale, length, accepted alphabet, uniqueness scope, and semantic format. Mark fields that require a standard syntax such as UUID, email, ISO date, or country code; a generic random string does not satisfy those contracts. Record which values are secrets and keep them outside this fixture workflow.

  2. Step 2

    Remove production values instead of mutating them

    Start from an empty fixture that retains only field names and structural relationships. Do not shuffle names, truncate account numbers, hash emails without a threat review, or preserve rare free text from a real row. Generate replacement values independently so the fixture cannot be joined back to a person or tenant through another copied field.

  3. Step 3

    Generate bounded representative valid values

    Use Number mode for documented inclusive ranges and fixed decimal steps. Use String mode for ordinary labels or mock keys, choose the smallest relevant alphabet, add a visible fixture_ prefix when useful, and require uniqueness only within the requested batch. Use a UUID generator for UUID fields and a dedicated password tool only when a password-policy test specifically needs one.

  4. Step 4

    Add boundary and invalid cases deliberately

    After creating representative valid rows, add exact minimum and maximum values, an empty or null value where relevant, one duplicate for a unique field, an overlength string, unsupported Unicode or delimiter cases, and values immediately outside numeric bounds. Random generation is not a substitute for this table because it may never hit the cases that define validation behavior.

  5. Step 5

    Export and validate the exact destination format

    Choose JSON for arrays or one-column CSV when those match the next step, then integrate values into the complete record structure. Run the file through the actual parser or staging importer. Confirm UTF-8 handling, CSV quote rules, decimal precision, JSON number limits, null representation, column order, and uniqueness enforcement rather than relying only on a visually correct preview.

  6. Step 6

    Freeze stable fixtures and document regeneration

    When snapshots or assertions expect exact values, save the reviewed output in version control instead of generating it during every test. Record the schema version, generation settings, hand-added boundary cases, expected accepted and rejected rows, and a condition for regeneration. Keep runtime randomness only in tests that explicitly verify probabilistic behavior and can assert invariants instead of exact values.

Example

Build a shareable order-import fixture

Input

Schema: orderKey string 12, quantity integer 1-20, unitPrice decimal(8,2) 0.01-999.99, UUID customerId, unique orderKey per file

Output

Ten valid records with fixture_ labels, bounded quantities and prices, fixed generated UUIDs, plus separate rows for quantity 0 and 21, price 0.00 and 1000.00, duplicate orderKey, empty customerId, overlength label, and malformed CSV quoting

Common mistakes

Anonymizing a production export in place

Partial masking can retain rare combinations, internal IDs, timestamps, free text, or relationships that identify a record. Build synthetic rows from the schema unless a reviewed anonymization program proves otherwise.

Treating random valid values as full coverage

A sample inside a range does not prove minimum, maximum, just-outside, duplicate, empty, encoding, or parser failure behavior. Keep a named boundary matrix beside representative fixtures.

Generating new values inside exact-output tests

Fresh randomness changes snapshots and expected payloads. Generate once and save the values, or use a documented seeded test-library generator when the test intentionally needs a repeatable sequence.

Using a generic string for a formatted field

A random alphanumeric body does not validate UUID versions, email syntax, date calendars, checksums, or country codes. Use a format-aware generator and still test invalid forms explicitly.

Calling generated fixture strings secure tokens

Fixture tools optimize shape, uniqueness within one batch, and export. Secrets need policy, entropy review, protected display, storage, rotation, and revocation that this workflow does not provide.

FAQ

Is synthetic data automatically anonymous?

Only when it is independently generated and does not preserve identifying values or relationships from real records. Review free text, timestamps, internal IDs, rare categories, and cross-field combinations before sharing a fixture.

Should every test use random data?

No. Stable unit, integration, and snapshot tests usually benefit from committed fixtures with explicit expected results. Runtime randomness is useful for property-based or fuzz testing when failures capture the seed or exact input and assertions check invariants.

How many representative values should I generate?

Use enough to exercise ordinary combinations and collection behavior, then add a small explicit boundary matrix. More random rows do not replace carefully selected minimum, maximum, duplicate, empty, malformed, and encoding cases.

Does unique output satisfy a database unique constraint?

It prevents duplicates only within one generated batch and configured value space. Another batch may repeat a value, concurrent inserts can conflict, and the database must enforce the actual constraint.

Can I share the exported fixture publicly?

Review the complete assembled file first. The generated values are synthetic, but surrounding comments, filenames, schema fields, copied payload sections, credentials, URLs, and metadata may still reveal private system information.