Document Workflow
Generate UUID v4 fixtures without copying production IDs
Build API, database, and event fixtures with locally generated RFC 9562 UUID v4 values, then validate and freeze those identifiers for safe, deterministic tests.
Written and tested by SimpleWebUtilsPublished: Reviewed:
How this workflow was checked
The UUID v4 Generator check used the exact input from “Replace three production-shaped API identifiers”. After “Map every identifier field and relationship” and “Choose the bounded batch and canonical format”, we matched the resulting values or file against the documented output and inspected the risks described by “Replacing the same entity inconsistently” and “Dropping the UNIQUE constraint because collisions are unlikely”.
All three replacement IDs matched lowercase canonical UUID v4 form, remained fixed in the saved fixture, and contained no copied production identifier.
Problem
Production-shaped fixtures often need UUID fields, but copying real customer, tenant, order, trace, or organization IDs into source control, screenshots, bug reports, and shared test systems creates an unnecessary link to live records. Replacing every value with 123 or a random-looking string is not a sound fix: code may require the canonical UUID grammar, version 4 and IETF variant bits, stable foreign-key relationships, or a database UNIQUE constraint. Generating new values during every test run introduces a different failure by making snapshots and golden files nondeterministic. A useful fixture workflow therefore needs to remove production identifiers, generate valid UUID v4 values locally, map each new value consistently, validate both syntax and relationships, freeze the reviewed fixture, and keep authentication and authorization tests separate because a UUID is not a secret or permission check.
Sources and standards
These authoritative references define the formats or security boundaries used in this workflow. Tool-specific verification is documented separately above.
- RFC 9562: Universally Unique IDentifiers (UUIDs)
RFC Editor / IETF
When to use this
- An API response fixture contains UUID primary keys, foreign keys, request IDs, or event IDs that should not reference production records.
- A database seed or migration example needs independently generated identifiers while retaining realistic UNIQUE and foreign-key behavior.
- A support ticket, screenshot, log excerpt, or reproduction package must replace live tenant and user IDs before sharing.
- A contract test needs canonical UUID v4 syntax but must produce the same expected output on every run.
- An offline client or distributed producer fixture allocates IDs before synchronization and needs an explicit conflict path.
Steps
- Step 1
Map every identifier field and relationship
List UUID fields, primary keys, foreign keys, correlation fields, nullability, required presentation, and uniqueness scope. Record whether the consumer requires lowercase canonical 8-4-4-4-12 text, accepts compact text, or uses a native binary UUID type. Mark repeated references that must receive the same replacement value.
- Step 2
Remove production identifiers before editing
Work from a sanitized copy and delete live UUIDs, names, email addresses, tokens, and payload details that are not required by the test. Do not paste production IDs into an online lookup service. The UUID generator requires no source input and creates values locally.
- Step 3
Choose the bounded batch and canonical format
Count the distinct replacement IDs rather than the number of field occurrences. Request 1 to 100 UUIDs, keep lowercase hyphenated output unless the schema says otherwise, and keep a small mapping table from fixture role to generated value.
- Step 4
Generate UUID v4 values locally
Run the generator once. It uses crypto.getRandomValues(), sets RFC 9562 version 4 and IETF variant bits, retries duplicates within the batch, and does not fall back to Math.random(). Copy or download the complete line-delimited result without sending generated identifiers to the server.
- Step 5
Validate syntax, count, and relationships
Confirm the output count, the version nibble 4, the variant nibble 8, 9, a, or b, and uniqueness inside the fixture. Replace every occurrence of the same old entity with the same new UUID, then parse the final JSON or CSV with the actual application parser.
- Step 6
Freeze a deterministic fixture
Commit the reviewed generated UUIDs as fixed fixture values. Do not call a UUID generator inside snapshot setup unless the assertion intentionally ignores or controls the random field. Stable IDs make diffs, failures, and expected relationships reproducible.
- Step 7
Exercise constraints and authorization separately
Load the fixture through the same validation path as production and retain database UNIQUE and foreign-key constraints. Add separate negative cases for duplicate IDs, malformed UUIDs, missing references, and unauthorized access; a valid UUID must never grant permission by itself.
Example
Replace three production-shaped API identifiers
Input
Schema: userId, organizationId, and requestId require lowercase canonical UUID v4 strings; userId belongs to organizationId; values must stay fixed in snapshots; no production IDs may remain.Output
{"userId":"3f2e2b6a-7f2c-4e3a-9a21-6e98785f4c20","organizationId":"7a6b3d94-44e3-4a70-85c0-31278f7d1b42","requestId":"b91d1c0e-6ef2-49e5-9f59-1f81d4f3be76"}Common mistakes
Generating new IDs during every assertion
Uncontrolled randomness changes snapshots and expected payloads on every run. Generate once and store fixed fixture values, or inject a deterministic UUID provider when the production code itself must be tested.
Replacing the same entity inconsistently
If one original organization ID appears in a parent record and three child rows, all four references need the same replacement. A mapping table prevents broken foreign-key relationships.
Dropping the UNIQUE constraint because collisions are unlikely
UUID v4 makes collisions extraordinarily unlikely, not impossible. A fixture should exercise the same unique constraint and conflict handling that protect production data.
Using any 36-character string as a UUID
Length alone does not establish UUID v4 syntax. Check hexadecimal groups, the version 4 nibble, the IETF variant, and the exact canonical or compact presentation required by the consumer.
Treating an opaque ID as authorization
A UUID is not a secret. Test authentication and authorization with explicit allowed and denied principals instead of assuming that knowledge of an ID grants access to the referenced record.
FAQ
Should a fixture generate UUIDs at runtime or store fixed values?
Store fixed UUIDs for snapshots, examples, golden files, and relationship-heavy fixtures. Runtime generation is appropriate only when the test controls the provider or explicitly verifies random allocation rather than exact output.
Can I copy UUIDs from production if I remove names and emails?
Avoid it. An identifier can still link a fixture, log, or screenshot back to a live tenant or record. Generate new UUID v4 values and preserve relationships with a local replacement map.
How do I verify that a generated value is UUID v4?
For canonical text, verify the 8-4-4-4-12 hexadecimal layout, a 4 at the start of the third group, and 8, 9, a, or b at the start of the fourth group. Then parse it with the same UUID library or database type used by the application.
Do I still need a database unique constraint?
Yes. Random generation lowers collision probability but does not enforce storage invariants. Keep the UNIQUE constraint and test how the application handles a rejected duplicate.
Does a UUID make an object URL private?
No. UUIDs are identifiers, not authorization. Protected objects need authentication, permission checks, and an intentional sharing or expiring-token design regardless of the ID format.
Are generated fixture UUIDs sent anywhere?
The generator creates them locally with Web Crypto and does not upload the values. Analytics is limited to aggregate settings such as count and format; generated UUID text is excluded.