Test Data Strategies and Fixtures
Your test suite uses a 500-line seed file copied from production three years ago. Half the tests depend on “John Doe” existing with email “john@test.com” and user ID 1. When someone adds a unique constraint on email, forty tests break. When the schema changes, the seed file requires a manual update that takes half a day. Test data is the foundation of your testing infrastructure — and most teams treat it as an afterthought.
What You’ll Walk Away With
Section titled “What You’ll Walk Away With”- Factory pattern implementations that generate consistent, realistic test data on demand
- Fixture management strategies for different test layers (unit, integration, E2E)
- Privacy-compliant data generation that mimics production patterns without real PII
- Database seeding workflows for integration and E2E tests
- Prompts for generating domain-specific test data factories
The Factory Pattern
Section titled “The Factory Pattern”Factories replace hardcoded test data with configurable generators that produce fresh, unique data for every test.
@src/lib/db/schema.tsGenerate test data factories for every entity in our database schema:
For each table, create a factory at /tests/factories/{entity}.factory.ts that:1. Uses @faker-js/faker for realistic data generation2. Has build() - returns a plain object (for unit tests, no DB)3. Has create(db) - inserts into the database and returns the record4. Has buildList(count) - generates an array of objects5. Has createList(db, count) - inserts multiple records6. Supports overrides: build({ email: 'specific@test.com' })7. Supports traits: build('admin'), build('suspended')8. Handles foreign keys: OrderFactory.create() auto-creates a User if needed9. Generates UNIQUE values (no collisions even with 1000 records)
Create a factory index at /tests/factories/index.ts that exports all factories.Follow our Drizzle ORM patterns for database insertions.claude "Read our database schema at /src/lib/db/schema.ts and generatetest data factories for every entity.
Save to /tests/factories/ with one file per entity.Each factory must:- Use faker.js for data generation- Support build() and create() patterns- Handle foreign key relationships automatically- Generate unique values per invocation- Support overrides and traits
After creating factories, verify they work by:1. Building 100 of each entity (no collisions)2. Creating 10 of each in the test database (relationships resolve)3. Running existing tests to verify compatibility"Generate test data factories for all database entities:1. Read the database schema2. Create factory files with build/create patterns3. Handle entity relationships and foreign keys4. Verify factories produce valid data5. Create a PR with the factory infrastructureFixture Strategies by Test Layer
Section titled “Fixture Strategies by Test Layer”Unit Tests: Build, Don’t Create
Section titled “Unit Tests: Build, Don’t Create”Unit tests should never touch the database. Use build() to create plain objects.
// Good: plain objects, no databaseconst user = UserFactory.build({ role: 'admin' });const result = authService.checkPermission(user, 'delete_users');expect(result).toBe(true);Integration Tests: Create with Isolation
Section titled “Integration Tests: Create with Isolation”Integration tests need database records but must not leak state between tests.
E2E Tests: Stable Reference Data
Section titled “E2E Tests: Stable Reference Data”E2E tests need predictable data that persists across the test run.
Privacy-Compliant Data Generation
Section titled “Privacy-Compliant Data Generation”Production-Like Without Real PII
Section titled “Production-Like Without Real PII”When This Breaks
Section titled “When This Breaks”“Tests fail because factories generate data that violates business rules.” Your factories need domain knowledge. Add validation to the factory: if a product is “outOfStock”, stock must be 0. If an order is “delivered”, it must have a shipped_at date before delivered_at. Encode business rules in the factory, not just random data.
“Creating test data is slow because of foreign key chains.” Batch insertions instead of creating one record at a time. Pre-create shared reference data (categories, roles) once in a beforeAll hook. Only create entity-specific data per test.
“The seed file keeps getting out of sync with schema changes.” Generate factories from the schema, not by hand. When the schema changes, regenerate: “Read the updated schema and update all factories to match. Add default values for new required columns.”
“We need production data for debugging but cannot use it because of PII.” Use the privacy-compliant generation approach. Create synthetic data that matches production distributions. For specific bug reproduction, anonymize the production record manually: replace the email with a faker email, the name with a faker name, but keep the structural data that reproduces the bug.