Agent skill
generate-factory
Auto-generate test data factories from schemas, types, or models. Use when creating test data infrastructure, setting up fixtures, or reducing test setup boilerplate.
Install this agent skill to your Project
npx add-skill https://github.com/jmagly/aiwg/tree/main/agentic/code/addons/testing-quality/skills/generate-factory
SKILL.md
Generate Factory Skill
Purpose
Auto-generate test data factories from database schemas, TypeScript interfaces, or model definitions. Factories produce realistic test data using Faker.js patterns, reducing test setup time by 60%.
Research Foundation
| Pattern | Source | Reference |
|---|---|---|
| Factory Pattern | ThoughtBot | FactoryBot |
| Faker.js | Open Source | fakerjs.dev |
| Test Data Management | ISTQB | CT-TAS Test Automation Strategy |
| Synthetic Data | Tonic.ai | Faker Best Practices |
When This Skill Applies
- User needs to create test data factories
- Setting up test infrastructure for new project
- Existing tests use hard-coded data
- Schema/model changes require test data updates
- Need realistic but deterministic test data
Trigger Phrases
| Natural Language | Action |
|---|---|
| "Generate factory for User model" | Create user factory |
| "Create test data factories" | Generate factories for all models |
| "Add faker to tests" | Integrate faker with existing tests |
| "Make test data realistic" | Convert hard-coded to factory |
| "Generate fixtures from schema" | Schema-aware factory generation |
Factory Concepts
Factory vs Fixture vs Mock
| Type | Purpose | When to Use |
|---|---|---|
| Factory | Generate dynamic test data | When you need many variations |
| Fixture | Static, predefined data | When exact values matter |
| Mock | Fake external dependencies | When isolating units |
Factory Features
// Basic factory
const user = userFactory.build();
// { id: 'uuid-1', name: 'John Doe', email: 'john@example.com' }
// With overrides
const admin = userFactory.build({ role: 'admin' });
// { id: 'uuid-2', name: 'Jane Doe', email: 'jane@example.com', role: 'admin' }
// Build multiple
const users = userFactory.buildList(5);
// Array of 5 users
// With traits
const inactiveUser = userFactory.build({}, { trait: 'inactive' });
// { id: 'uuid-3', ..., status: 'inactive', deactivatedAt: Date }
// With relationships
const userWithOrders = userFactory.build({}, { with: ['orders'] });
// { id: 'uuid-4', ..., orders: [{ id: 'order-1', ... }] }
Generation Process
1. Analyze Source
Detect schema/type from:
- TypeScript interfaces
- Prisma schema
- JSON Schema
- Database migrations
- OpenAPI specs
// Input: TypeScript interface
interface User {
id: string;
name: string;
email: string;
age: number;
role: 'admin' | 'user' | 'guest';
createdAt: Date;
preferences?: UserPreferences;
}
2. Map Types to Faker
const TYPE_MAPPING = {
// Primitives
'string': 'faker.string.alphanumeric(10)',
'number': 'faker.number.int({ min: 0, max: 100 })',
'boolean': 'faker.datatype.boolean()',
'Date': 'faker.date.past()',
// Named fields (semantic mapping)
'id': 'faker.string.uuid()',
'name': 'faker.person.fullName()',
'email': 'faker.internet.email()',
'phone': 'faker.phone.number()',
'address': 'faker.location.streetAddress()',
'age': 'faker.number.int({ min: 18, max: 80 })',
'createdAt': 'faker.date.past()',
'updatedAt': 'faker.date.recent()',
// Enums
'role': 'faker.helpers.arrayElement(["admin", "user", "guest"])',
};
3. Generate Factory
// Generated: factories/user.factory.ts
import { faker } from '@faker-js/faker';
import type { User } from '../types';
export const userFactory = {
/**
* Build a single User with optional overrides
*/
build: (overrides: Partial<User> = {}): User => ({
id: faker.string.uuid(),
name: faker.person.fullName(),
email: faker.internet.email(),
age: faker.number.int({ min: 18, max: 80 }),
role: faker.helpers.arrayElement(['admin', 'user', 'guest']),
createdAt: faker.date.past(),
...overrides,
}),
/**
* Build multiple Users
*/
buildList: (count: number, overrides: Partial<User> = {}): User[] =>
Array.from({ length: count }, () => userFactory.build(overrides)),
/**
* Traits for common variations
*/
traits: {
admin: { role: 'admin' as const },
inactive: {
status: 'inactive',
deactivatedAt: faker.date.past(),
},
newUser: {
createdAt: faker.date.recent(),
},
},
/**
* Build with trait
*/
buildWithTrait: (trait: keyof typeof userFactory.traits, overrides: Partial<User> = {}): User =>
userFactory.build({ ...userFactory.traits[trait], ...overrides }),
};
4. Generate Related Factories
For entities with relationships:
// factories/order.factory.ts
import { faker } from '@faker-js/faker';
import { userFactory } from './user.factory';
export const orderFactory = {
build: (overrides = {}) => ({
id: faker.string.uuid(),
userId: faker.string.uuid(),
items: [],
total: faker.number.float({ min: 10, max: 500, fractionDigits: 2 }),
status: faker.helpers.arrayElement(['pending', 'shipped', 'delivered']),
createdAt: faker.date.past(),
...overrides,
}),
/**
* Build with related user
*/
buildWithUser: (overrides = {}) => {
const user = userFactory.build();
return {
...orderFactory.build({ userId: user.id, ...overrides }),
user,
};
},
};
Output Format
## Factory Generation Report
**Source**: `src/types/user.ts`
**Output**: `test/factories/user.factory.ts`
### Generated Factory
```typescript
import { faker } from '@faker-js/faker';
import type { User } from '../../src/types';
export const userFactory = {
build: (overrides: Partial<User> = {}): User => ({
id: faker.string.uuid(),
name: faker.person.fullName(),
email: faker.internet.email(),
age: faker.number.int({ min: 18, max: 80 }),
role: faker.helpers.arrayElement(['admin', 'user', 'guest']),
createdAt: faker.date.past(),
preferences: null,
...overrides,
}),
buildList: (count: number, overrides: Partial<User> = {}): User[] =>
Array.from({ length: count }, () => userFactory.build(overrides)),
traits: {
admin: { role: 'admin' as const },
inactive: { status: 'inactive' },
},
};
Field Mappings
| Field | Type | Faker Method |
|---|---|---|
| id | string | faker.string.uuid() |
| name | string | faker.person.fullName() |
| string | faker.internet.email() |
|
| age | number | faker.number.int({ min: 18, max: 80 }) |
| role | enum | faker.helpers.arrayElement([...]) |
| createdAt | Date | faker.date.past() |
Usage Examples
// Basic usage
const user = userFactory.build();
// With override
const admin = userFactory.build({ role: 'admin' });
// Multiple users
const users = userFactory.buildList(10);
// With trait
const inactive = userFactory.build(userFactory.traits.inactive);
Dependencies Added
{
"devDependencies": {
"@faker-js/faker": "^8.0.0"
}
}
## Deterministic Mode
For tests requiring reproducible data:
```typescript
// Set seed for reproducible data
import { faker } from '@faker-js/faker';
beforeEach(() => {
faker.seed(12345); // Same data every run
});
// Or per-factory
export const userFactory = {
buildDeterministic: (seed: number, overrides = {}) => {
faker.seed(seed);
return userFactory.build(overrides);
},
};
Batch Generation
Generate factories for all models:
# From Prisma schema
npx generate-factory --source prisma/schema.prisma --output test/factories/
# From TypeScript types
npx generate-factory --source src/types/ --output test/factories/
Integration Points
- Works with
tdd-enforcefor test data requirements - Used by Test Engineer for test creation
- Feeds into integration test setup
- Compatible with database seeders
Script Reference
factory_generator.py
Generate factory from schema:
python scripts/factory_generator.py --source src/types/user.ts
batch_generate.py
Generate all factories:
python scripts/batch_generate.py --source src/types/ --output test/factories/
References
- @$AIWG_ROOT/agentic/code/addons/testing-quality/README.md — Testing quality addon overview
- @$AIWG_ROOT/agentic/code/frameworks/sdlc-complete/README.md — SDLC framework context for test infrastructure
- @$AIWG_ROOT/agentic/code/addons/aiwg-utils/rules/research-before-decision.md — Research-first for schema and type analysis
- @$AIWG_ROOT/docs/cli-reference.md — CLI reference
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
research-document
Generate summaries and literature notes from research papers
research-archive
Package research artifacts for long-term archival
research-cite
Format citations and generate bibliographies
induct-research
Induct research sources into a research repository. Point at an issue, a single file, a directory of papers, or a URI and the skill reads, annotates, and files structured induction tasks — one per source. Similar to address-issues but for research corpora instead of code backlogs.
research-provenance
Query provenance chains and artifact relationships
research-quality
Assess source quality using GRADE methodology
Didn't find tool you were looking for?