Agent skill

Phy Test Data Factory

by LeoYeAI in LeoYeAI/openclaw-master-skills

Schema-driven test data factory generator. An agent skill from LeoYeAI/openclaw-master-skills.

Apache-2.0Auto-check passedTesting & QA

Install Phy Test Data Factory

skills CLI
$ npx skills add LeoYeAI/openclaw-master-skills --skill phy-test-data-factory -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install LeoYeAI/openclaw-master-skills phy-test-data-factory --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/LeoYeAI/openclaw-master-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/phy-test-data-factory .claude/skills/phy-test-data-factory && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
phy-test-data-factory
GitHub stars
2.2k
Token cost
~5.5k tokens
SKILL.md length
186 words
Files
2
Skills in repo
1,235
Repo updated
First seen
Licence
Apache-2.0

At a glance

Schema-driven test data factory generator. An agent skill from LeoYeAI/openclaw-master-skills.

  • Works in 5 steps: Detect and Parse Schema → Map Types to Faker Functions → Detect Relationship Order → …
  • Generate test data
  • SKILL.md covers Trigger Phrases, How to Provide Input, Step 1: Detect and Parse Schema and Step 2: Map Types to Faker…, plus 4 more sections
  • Calls pip, npm and node

What it does

Phy Test Data Factory is an agent skill from LeoYeAI/openclaw-master-skills. Schema-driven test data factory generator. Reads your database schema or model definitions — Prisma schema, SQLAlchemy models, Django models, TypeORM entities, Zod schemas, Pydantic models, or raw SQL DDL — and generates ready-to-use factory functions with realistic fake data. Outputs TypeScript factory files using Faker.js, Python conftest.py using factoryboy + Faker, or raw SQL INSERT seed scripts. Respects foreign key relationships (seeds parents before children), handles enums, nullable fields, unique…

Its SKILL.md is about 5.5k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `_meta.json`).

It sits in Testing & QA, covering Test data and fixtures. It works with SQL, Prisma, Python and TypeScript. The repository describes itself as: 🧠 Curated collection of 1209+ best OpenClaw skills — weekly updated by MyClaw.ai. The licence is Apache-2.0.

When your agent uses it

  • Generate test data
  • Factory functions
  • Fake data from schema
  • /test-data-factory

Example prompts

  • “generate test data”
  • “seed database”
  • “test fixtures”
  • “/phy-test-data-factory”

Requirements

  • Python 3
  • Node.js

Workflow steps

5 steps, taken from the step headings in SKILL.md.

  1. Detect and Parse Schema
  2. Map Types to Faker Functions
  3. Detect Relationship Order
  4. Generate Factory Code
  5. Output Report

What it can do on your machine

Read from SKILL.md and the folder at commit e5199b5. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • pip
    • npm
    • node
    • python3

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use pip and npm, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Phy Test Data Factory loads about 5.5k tokens when it runs. Until then it costs about 208 tokens; SKILL.md has 186 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~208
When it runs · the whole SKILL.md, loaded when a task matches
~5.5k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from LeoYeAI/openclaw-master-skills at commit e5199b5, republished under its Apache-2.0 licence (© LeoYeAI). 186 words, ~5,538 tokens.

Download SKILL.mdSave it as .claude/skills/phy-test-data-factory/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
phy-test-data-factory
description
Schema-driven test data factory generator. Reads your database schema or model definitions — Prisma schema, SQLAlchemy models, Django models, TypeORM entities, Zod schemas, Pydantic models, or raw SQL DDL — and generates ready-to-use factory functions with realistic fake data. Outputs TypeScript factory files using Faker.js, Python conftest.py using factory_boy + Faker, or raw SQL INSERT seed scripts. Respects foreign key relationships (seeds parents before children), handles enums, nullable fields, unique constraints, and generates edge-case variants (empty strings, max-length values, boundary dates). Zero external API — pure local file analysis + code generation. Triggers on "generate test data", "seed database", "test fixtures", "factory functions", "fake data from schema", "/test-data-factory".
license
Apache-2.0
metadata.author
PHY041
metadata.version
1.0.0
metadata.tags
testing, test-data, fixtures, faker, factory-boy, prisma, sqlalchemy, django, seed-data, developer-tools

Test Data Factory

Writing test setup is slower than writing the test itself. You have a User model with 12 fields, a Post model that requires a User, and an Order model that requires both. Every test file re-invents the same createTestUser() boilerplate — with slightly different hardcoded values that don't cover edge cases.

Paste your schema and get a complete factory module: realistic Faker-powered defaults for every field, relationship-aware ordering, and one-line overrides for specific test scenarios.

Reads any schema format. Outputs TypeScript, Python, or SQL. Zero external APIs.


Trigger Phrases

  • "generate test data", "seed my database", "test fixtures"
  • "factory functions", "fake data from schema", "test data setup"
  • "create test factories", "Faker from schema", "factory_boy setup"
  • "generate seed data", "populate test database"
  • "I need fake users/orders/products for testing"
  • "/test-data-factory"

How to Provide Input

bash
# Option 1: Prisma schema
/test-data-factory schema.prisma
/test-data-factory prisma/schema.prisma

# Option 2: SQLAlchemy / Django models file
/test-data-factory models.py
/test-data-factory app/models.py

# Option 3: TypeORM entities directory
/test-data-factory src/entities/

# Option 4: Zod schemas file
/test-data-factory src/schemas/user.schema.ts

# Option 5: Raw SQL DDL
/test-data-factory --sql migrations/001_initial.sql

# Option 6: Output format override
/test-data-factory schema.prisma --output typescript
/test-data-factory models.py --output python
/test-data-factory schema.prisma --output sql

# Option 7: Include edge-case variants
/test-data-factory schema.prisma --edge-cases

# Option 8: Specific count
/test-data-factory schema.prisma --count 50

Step 1: Detect and Parse Schema

Prisma Schema Parser
python
import re
from dataclasses import dataclass, field
from typing import Any

@dataclass
class PrismaField:
    name: str
    type: str
    is_optional: bool = False
    is_list: bool = False
    is_id: bool = False
    is_unique: bool = False
    is_auto: bool = False
    default: Any = None
    relation: str | None = None
    enum_values: list[str] = field(default_factory=list)

def parse_prisma_schema(schema_text: str) -> dict:
    """Parse Prisma schema into model definitions."""
    models = {}
    enums = {}

    # Parse enums first
    for enum_match in re.finditer(r'enum\s+(\w+)\s*\{([^}]+)\}', schema_text, re.DOTALL):
        enum_name = enum_match.group(1)
        values = [v.strip() for v in enum_match.group(2).split('\n')
                  if v.strip() and not v.strip().startswith('//')]
        enums[enum_name] = values

    # Parse models
    for model_match in re.finditer(r'model\s+(\w+)\s*\{([^}]+)\}', schema_text, re.DOTALL):
        model_name = model_match.group(1)
        body = model_match.group(2)
        fields = []

        for line in body.split('\n'):
            line = line.strip()
            if not line or line.startswith('//') or line.startswith('@@'):
                continue
            # Parse field: name type? modifiers
            parts = line.split()
            if len(parts) < 2:
                continue

            fname = parts[0]
            ftype_raw = parts[1]

            is_optional = ftype_raw.endswith('?')
            is_list = ftype_raw.endswith('[]')
            ftype = ftype_raw.rstrip('?').rstrip('[]')

            is_id = '@id' in line
            is_unique = '@unique' in line
            is_auto = '@default(autoincrement())' in line or '@default(auto())' in line or '@default(uuid())' in line or '@default(cuid())' in line
            is_relation = '@relation' in line

            default_match = re.search(r'@default\((.+?)\)', line)
            default_val = default_match.group(1) if default_match else None

            fields.append(PrismaField(
                name=fname,
                type=ftype,
                is_optional=is_optional,
                is_list=is_list,
                is_id=is_id,
                is_unique=is_unique,
                is_auto=is_auto,
                default=default_val,
                relation=ftype if is_relation and ftype[0].isupper() else None,
                enum_values=enums.get(ftype, []),
            ))

        models[model_name] = fields

    return {'models': models, 'enums': enums}
SQL DDL Parser
python
def parse_sql_ddl(sql_text: str) -> dict:
    """Parse CREATE TABLE statements."""
    models = {}

    for table_match in re.finditer(
        r'CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"]?(\w+)[`"]?\s*\(([^;]+)\)',
        sql_text, re.IGNORECASE | re.DOTALL
    ):
        table_name = table_match.group(1)
        columns_text = table_match.group(2)
        fields = []

        for col_line in columns_text.split(','):
            col_line = col_line.strip()
            if not col_line or col_line.upper().startswith(('PRIMARY', 'FOREIGN', 'UNIQUE', 'INDEX', 'KEY', 'CONSTRAINT')):
                continue

            col_match = re.match(r'[`"]?(\w+)[`"]?\s+(\w+)(\(\d+\))?(.*)$', col_line, re.IGNORECASE)
            if not col_match:
                continue

            fname = col_match.group(1)
            ftype = col_match.group(2).upper()
            rest = col_match.group(4).upper()
            is_nullable = 'NOT NULL' not in rest
            is_auto = 'AUTO_INCREMENT' in rest or 'SERIAL' in ftype
            is_unique = 'UNIQUE' in rest

            fields.append(PrismaField(
                name=fname,
                type=ftype,
                is_optional=is_nullable,
                is_auto=is_auto,
                is_unique=is_unique,
            ))

        models[table_name] = fields

    return {'models': models, 'enums': {}}

Step 2: Map Types to Faker Functions

python
# Prisma/TypeScript type → Faker.js function
FAKER_JS_MAP = {
    # Primitives
    'String':   'faker.lorem.words(3)',
    'Int':      'faker.number.int({ min: 1, max: 10000 })',
    'Float':    'faker.number.float({ min: 0, max: 1000, fractionDigits: 2 })',
    'Boolean':  'faker.datatype.boolean()',
    'DateTime': 'faker.date.recent({ days: 30 })',
    'BigInt':   'BigInt(faker.number.int({ min: 1, max: 1000000 }))',
    'Json':     '{}',
    'Bytes':    'Buffer.from(faker.string.alphanumeric(16))',

    # Semantic overrides (based on field name)
    'email':       'faker.internet.email()',
    'name':        'faker.person.fullName()',
    'firstName':   'faker.person.firstName()',
    'lastName':    'faker.person.lastName()',
    'username':    'faker.internet.username()',
    'password':    'faker.internet.password({ length: 12 })',
    'phone':       'faker.phone.number()',
    'address':     'faker.location.streetAddress()',
    'city':        'faker.location.city()',
    'country':     'faker.location.country()',
    'zipCode':     'faker.location.zipCode()',
    'url':         'faker.internet.url()',
    'imageUrl':    'faker.image.url()',
    'avatar':      'faker.image.avatar()',
    'bio':         'faker.lorem.paragraph()',
    'description': 'faker.lorem.sentences(2)',
    'title':       'faker.lorem.sentence()',
    'slug':        'faker.helpers.slugify(faker.lorem.words(3))',
    'color':       'faker.color.human()',
    'uuid':        'faker.string.uuid()',
    'ip':          'faker.internet.ip()',
    'createdAt':   'faker.date.past({ years: 1 })',
    'updatedAt':   'new Date()',
    'deletedAt':   'null',
    'publishedAt': 'faker.date.recent({ days: 90 })',
    'price':       'faker.number.float({ min: 0.99, max: 999.99, fractionDigits: 2 })',
    'amount':      'faker.number.int({ min: 1, max: 10000 })',
    'quantity':    'faker.number.int({ min: 1, max: 100 })',
    'score':       'faker.number.float({ min: 0, max: 5, fractionDigits: 1 })',
    'rating':      'faker.number.int({ min: 1, max: 5 })',
    'status':      None,  # replaced by enum values
    'role':        None,  # replaced by enum values
    'type':        None,  # replaced by enum values
}

# Same mapping for Python Faker
FAKER_PY_MAP = {
    'String': "fake.sentence(nb_words=3)",
    'str':    "fake.sentence(nb_words=3)",
    'Int':    "fake.random_int(min=1, max=10000)",
    'int':    "fake.random_int(min=1, max=10000)",
    'Float':  "round(random.uniform(0, 1000), 2)",
    'float':  "round(random.uniform(0, 1000), 2)",
    'bool':   "fake.boolean()",
    'datetime': "fake.date_time_this_year()",
    'email':  "fake.email()",
    'name':   "fake.name()",
    'phone':  "fake.phone_number()",
    'url':    "fake.url()",
    'uuid':   "str(uuid.uuid4())",
    'price':  "round(random.uniform(0.99, 999.99), 2)",
}

def get_faker_value(field_name: str, field_type: str, enum_values: list, lang: str = 'ts') -> str:
    """Get the Faker expression for a field."""
    mapper = FAKER_JS_MAP if lang == 'ts' else FAKER_PY_MAP
    prefix = 'faker.' if lang == 'ts' else 'fake.'

    # Enum field: pick from enum values
    if enum_values:
        if lang == 'ts':
            return f'faker.helpers.arrayElement([{", ".join(repr(v) for v in enum_values)}])'
        else:
            return f'random.choice([{", ".join(repr(v) for v in enum_values)}])'

    # Check semantic field name first
    for semantic_key, expr in mapper.items():
        if field_name.lower().endswith(semantic_key.lower()) or field_name.lower() == semantic_key.lower():
            if expr:
                return expr

    # Fall back to type mapping
    return mapper.get(field_type, f'"TODO: {field_type}"')

Step 3: Detect Relationship Order

Topologically sort models so parents are created before children:

python
def topological_sort(models: dict) -> list[str]:
    """Return model names in dependency order (parents first)."""
    from collections import defaultdict, deque

    graph = defaultdict(list)
    in_degree = {name: 0 for name in models}

    for model_name, fields in models.items():
        for field in fields:
            if field.relation and field.relation in models and not field.is_optional:
                # model_name depends on field.relation
                graph[field.relation].append(model_name)
                in_degree[model_name] += 1

    queue = deque([m for m, d in in_degree.items() if d == 0])
    order = []

    while queue:
        model = queue.popleft()
        order.append(model)
        for dependent in graph[model]:
            in_degree[dependent] -= 1
            if in_degree[dependent] == 0:
                queue.append(dependent)

    # Append any remaining (circular deps)
    for m in models:
        if m not in order:
            order.append(m)

    return order

Step 4: Generate Factory Code

TypeScript Output (Faker.js)
typescript
// Generated by phy-test-data-factory
// Install: npm install -D @faker-js/faker

import { faker } from '@faker-js/faker';
import { PrismaClient, UserRole, PostStatus } from '@prisma/client';

const prisma = new PrismaClient();

// ─── User Factory ────────────────────────────────────────────────────────────

export interface CreateUserOptions {
  id?: string;
  email?: string;
  name?: string;
  role?: UserRole;
  createdAt?: Date;
}

export function buildUser(overrides: CreateUserOptions = {}) {
  return {
    id:        faker.string.uuid(),
    email:     faker.internet.email(),
    name:      faker.person.fullName(),
    username:  faker.internet.username(),
    password:  faker.internet.password({ length: 12 }),
    bio:       faker.lorem.paragraph(),
    avatarUrl: faker.image.avatar(),
    role:      faker.helpers.arrayElement(['USER', 'ADMIN', 'MODERATOR'] as UserRole[]),
    isActive:  true,
    createdAt: faker.date.past({ years: 1 }),
    updatedAt: new Date(),
    ...overrides,
  };
}

export async function createUser(overrides: CreateUserOptions = {}) {
  return prisma.user.create({ data: buildUser(overrides) });
}

// ─── Post Factory ─────────────────────────────────────────────────────────────

export interface CreatePostOptions {
  id?: string;
  title?: string;
  content?: string;
  authorId?: string;       // Will create a User if not provided
  status?: PostStatus;
}

export async function createPost(overrides: CreatePostOptions = {}) {
  const authorId = overrides.authorId ?? (await createUser()).id;
  return prisma.post.create({
    data: {
      id:          faker.string.uuid(),
      title:       faker.lorem.sentence(),
      slug:        faker.helpers.slugify(faker.lorem.words(4)),
      content:     faker.lorem.paragraphs(3),
      excerpt:     faker.lorem.sentences(2),
      status:      faker.helpers.arrayElement(['DRAFT', 'PUBLISHED', 'ARCHIVED'] as PostStatus[]),
      publishedAt: faker.date.recent({ days: 90 }),
      authorId,
      createdAt:   faker.date.past({ years: 1 }),
      updatedAt:   new Date(),
      ...overrides,
    },
  });
}

// ─── Order Factory ────────────────────────────────────────────────────────────

export interface CreateOrderOptions {
  id?: string;
  userId?: string;
  total?: number;
  status?: 'PENDING' | 'CONFIRMED' | 'SHIPPED' | 'DELIVERED' | 'CANCELLED';
}

export async function createOrder(overrides: CreateOrderOptions = {}) {
  const userId = overrides.userId ?? (await createUser()).id;
  return prisma.order.create({
    data: {
      id:      faker.string.uuid(),
      userId,
      total:   faker.number.float({ min: 9.99, max: 999.99, fractionDigits: 2 }),
      status:  faker.helpers.arrayElement(['PENDING', 'CONFIRMED', 'SHIPPED', 'DELIVERED', 'CANCELLED']),
      address: faker.location.streetAddress(),
      city:    faker.location.city(),
      country: faker.location.country(),
      createdAt: faker.date.past({ years: 1 }),
      updatedAt: new Date(),
      ...overrides,
    },
  });
}

// ─── Bulk creation helpers ────────────────────────────────────────────────────

export async function createUsers(count: number, overrides: CreateUserOptions = {}) {
  return Promise.all(Array.from({ length: count }, () => createUser(overrides)));
}

export async function createPosts(count: number, overrides: CreatePostOptions = {}) {
  return Promise.all(Array.from({ length: count }, () => createPost(overrides)));
}

// ─── Teardown ─────────────────────────────────────────────────────────────────

export async function clearTestData() {
  // Delete in reverse dependency order (children before parents)
  await prisma.order.deleteMany();
  await prisma.post.deleteMany();
  await prisma.user.deleteMany();
}
Python Output (factory_boy)
python
# Generated by phy-test-data-factory
# Install: pip install factory_boy faker

import uuid, random
from datetime import datetime
import factory
from factory import Faker, SubFactory, LazyFunction
from factory.django import DjangoModelFactory  # or SQLAlchemyModelFactory
from myapp.models import User, Post, Order, UserRole, PostStatus

class UserFactory(DjangoModelFactory):
    class Meta:
        model = User

    id           = LazyFunction(lambda: str(uuid.uuid4()))
    email        = Faker('email')
    name         = Faker('name')
    username     = Faker('user_name')
    bio          = Faker('paragraph')
    avatar_url   = Faker('image_url')
    role         = factory.Iterator([r.value for r in UserRole])
    is_active    = True
    created_at   = Faker('date_time_this_year')
    updated_at   = LazyFunction(datetime.utcnow)

class PostFactory(DjangoModelFactory):
    class Meta:
        model = Post

    id           = LazyFunction(lambda: str(uuid.uuid4()))
    title        = Faker('sentence', nb_words=6)
    slug         = factory.LazyAttribute(lambda o: o.title.lower().replace(' ', '-').replace(',', ''))
    content      = Faker('paragraphs', nb=3, as_list=False)
    excerpt      = Faker('sentences', nb=2, as_list=False)
    status       = factory.Iterator([s.value for s in PostStatus])
    author       = SubFactory(UserFactory)
    published_at = Faker('date_time_this_month')
    created_at   = Faker('date_time_this_year')
    updated_at   = LazyFunction(datetime.utcnow)

class OrderFactory(DjangoModelFactory):
    class Meta:
        model = Order

    id       = LazyFunction(lambda: str(uuid.uuid4()))
    user     = SubFactory(UserFactory)
    total    = LazyFunction(lambda: round(random.uniform(9.99, 999.99), 2))
    status   = factory.Iterator(['PENDING', 'CONFIRMED', 'SHIPPED', 'DELIVERED'])
    address  = Faker('street_address')
    city     = Faker('city')
    country  = Faker('country')
    created_at = Faker('date_time_this_year')
    updated_at = LazyFunction(datetime.utcnow)


# Usage in pytest conftest.py:
#
# @pytest.fixture
# def user(db):
#     return UserFactory()
#
# @pytest.fixture
# def post_with_author(db):
#     return PostFactory()  # auto-creates a User via SubFactory
#
# @pytest.fixture
# def many_orders(db):
#     return OrderFactory.create_batch(20)
SQL Seed Output
sql
-- Generated by phy-test-data-factory
-- Seed data for: users, posts, orders
-- Insert in dependency order (parents first)

-- Users (10 rows)
INSERT INTO users (id, email, name, role, is_active, created_at) VALUES
  ('usr_001', 'alice@example.com', 'Alice Johnson', 'USER', true, '2026-01-15 09:30:00'),
  ('usr_002', 'bob@example.com', 'Bob Smith', 'ADMIN', true, '2026-01-20 14:00:00'),
  ('usr_003', 'carol@example.com', 'Carol Williams', 'USER', true, '2026-02-01 11:00:00'),
  -- ... (7 more rows)

-- Posts (20 rows, requires users above)
INSERT INTO posts (id, title, slug, status, author_id, created_at) VALUES
  ('post_001', 'Getting Started with Testing', 'getting-started-testing', 'PUBLISHED', 'usr_001', '2026-02-10 10:00:00'),
  ('post_002', 'Advanced Patterns in TypeScript', 'advanced-typescript', 'DRAFT', 'usr_002', '2026-02-15 11:30:00'),
  -- ... (18 more rows)

Step 5: Output Report

markdown
## Test Data Factory — Generated
Schema: prisma/schema.prisma | Models: User, Post, Comment, Order, Tag
Output: src/test/factories/index.ts

---

### Models Processed (dependency order)

| Model | Fields | Relationships | Factory Type |
|-------|--------|--------------|-------------|
| User | 14 fields | — (root) | createUser() |
| Tag | 4 fields | — (root) | createTag() |
| Post | 11 fields | → User (author) | createPost() |
| Comment | 8 fields | → User, → Post | createComment() |
| Order | 9 fields | → User | createOrder() |

---

### Generated Files

- `src/test/factories/index.ts` — all factory functions
- `src/test/factories/builders.ts` — plain object builders (no DB write)
- `src/test/setup.ts` — jest/vitest beforeAll/afterAll with clearTestData()

---

### Auto-Detected Semantic Mappings

| Field | Detected As | Faker Function Used |
|-------|------------|---------------------|
| `email` | Email address | `faker.internet.email()` |
| `avatarUrl` | Image URL | `faker.image.avatar()` |
| `publishedAt` | Recent date | `faker.date.recent({ days: 90 })` |
| `role` | Enum (USER/ADMIN/MOD) | `faker.helpers.arrayElement([...])` |
| `slug` | URL slug | `faker.helpers.slugify(faker.lorem.words(3))` |
| `price` | Currency amount | `faker.number.float({ fractionDigits: 2 })` |

---

### Quick Usage

```typescript
import { createUser, createPost, createOrder, clearTestData } from './factories';

// Single record
const user = await createUser();

// With overrides
const adminUser = await createUser({ role: 'ADMIN', email: 'admin@test.com' });

// Relationships handled automatically
const post = await createPost();       // creates a User internally
const post2 = await createPost({ authorId: user.id });  // reuse existing User

// Batch creation
const orders = await createOrders(50);

// Teardown
afterAll(clearTestData);

---

## Edge Case Variants

With `--edge-cases`, generate additional factory variants for boundary testing:

```typescript
// Generated edge-case builders for User model:

export const edgeCaseUsers = {
  withMinLengthFields: () => buildUser({
    email: 'a@b.co',
    name: 'A',
    bio: '',
  }),
  withMaxLengthFields: () => buildUser({
    email: 'a'.repeat(243) + '@b.co',  // 255 chars total
    name: 'A'.repeat(255),
    bio: 'x'.repeat(5000),
  }),
  withNullableFieldsNull: () => buildUser({
    bio: null,
    avatarUrl: null,
    phoneNumber: null,
  }),
  withSpecialCharacters: () => buildUser({
    name: "O'Brien-Smith, Jr.",
    bio: '<script>alert("xss")</script>',  // for XSS testing
  }),
  withUnicodeContent: () => buildUser({
    name: '张伟',
    bio: '日本語テキスト with emoji 🎉',
  }),
  withPastDates: () => buildUser({
    createdAt: new Date('2000-01-01'),
  }),
  withFutureDates: () => buildUser({
    createdAt: new Date('2099-12-31'),
  }),
};

Install Dependencies

bash
# TypeScript / JavaScript
npm install -D @faker-js/faker

# Python (Django)
pip install factory_boy faker

# Python (SQLAlchemy)
pip install factory_boy faker sqlalchemy

# Verify installation
node -e "const { faker } = require('@faker-js/faker'); console.log(faker.person.fullName())"
python3 -c "import factory; print('factory_boy ready')"

© LeoYeAI, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file in skills/phy-test-data-factory of LeoYeAI/openclaw-master-skills.

  • SKILL.md
  • _meta.json

Open the folder on GitHubat commit e5199b5

Compare with similar skills

Phy Test Data Factory next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Phy Test Data Factory compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Phy Test Data Factory this skillLeoYeAI/openclaw-master-skills2.2k—~5.5kAutomated safety check: PassApache-2.0
Django Filter Benchmarksaleor/saleor23k—~2.3kAutomated safety check: PassBSD-3-Clause
Fastapiericrisco/rsc-harness174—~5kAutomated safety check: NotesMIT
Pytestmathiasertl/django-ca158—~924Automated safety check: PassGPL-3.0
Dummy Dataset Generatorphuryn/pm-skills27k—~983Automated safety check: PassMIT
Dummy Datasetkillvxk/pm-skills-zh167—~595Automated safety check: PassMIT

Similar skills

  • Benchmarks Django ORM filters in Saleor by generating bulk data, extracting the SQL and running EXPLAIN ANALYZE to check index usage.

    23k GitHub stars~2.3k tokensUpdated today
    DatabasesAuto-check passed
  • Fastapi

    ericrisco/rsc-harness

    A skill your agent uses when building, reviewing, testing, securing or shipping a FastAPI / async Python service — routers, Pydantic v2 schemas, dependency injection, async SQLAlchemy 2.0…

    174 GitHub stars~5k tokensUpdated yesterday
    Backend & APIsAuto-check: notes
  • Pytest

    mathiasertl/django-ca

    Instructions for running, writing, and maintaining tests in this project

    158 GitHub stars~924 tokensUpdated 5 days ago
    Testing & QAAuto-check passed
  • Dummy Dataset Generator

    phuryn/pm-skills

    Generates realistic test datasets with custom columns, row counts and business constraints, output as CSV, JSON, SQL inserts or a runnable Python script.

    27k GitHub stars~983 tokensUpdated 24 days ago
    Testing & QAAuto-check passed
  • Dummy Dataset

    killvxk/pm-skills-zh

    生成用于测试的逼真虚拟数据集,支持自定义列、约束条件及输出格式(CSV、JSON、SQL、Python 脚本)。适用于创建测试数据、构建模拟数据集,或为开发和演示生成示例数据。

    167 GitHub stars~595 tokensUpdated 6 mo ago
    DatabasesAuto-check passed
  • Testing Strategies

    ancoleman/ai-design-components

    Strategic guidance for choosing and implementing testing approaches across the test pyramid.

    526 GitHub stars~3.8k tokensUpdated 10 mo ago
    Testing & QAAuto-check passed

More from LeoYeAI/openclaw-master-skills

All 1,235 skills in this repo
  • DevOps Pipeline Management

    LeoYeAI/openclaw-master-skills

    Manages pipelines on a DevOps quality and efficiency platform through its OpenAPI: list workspaces and templates, create, update, run and cancel pipelines, and read run records.

    2.2k GitHub stars~4.2k tokensUpdated 2 mo ago
    Auto-check: notes
  • Feishu Document Collaboration

    LeoYeAI/openclaw-master-skills

    Patches OpenClaw's Feishu extension so an edited document triggers an isolated agent session that reads the doc and replies inline, turning it into a live chat space.

    2.2k GitHub stars~2k tokensUpdated 2 mo ago
    Auto-check passed
  • Files Memory System

    LeoYeAI/openclaw-master-skills

    Multi-context memory management system for OpenClaw agents with group-isolated storage, global shared memory, workspace organization, and group-specific skills isolation.

    2.2k GitHub stars~3.8k tokensUpdated 2 mo ago
    Auto-check passed
  • GEO-Claw AI Visibility Agent

    LeoYeAI/openclaw-master-skills

    Runs a brand's AI-search visibility work end to end: diagnosing how AI platforms represent it, repositioning it, producing AI-optimized content and monitoring ongoing mentions.

    2.2k GitHub stars~4.7k tokensUpdated 2 mo ago
    Auto-check passed
  • Google Workspace CLI

    LeoYeAI/openclaw-master-skills

    Installs and authenticates the gws CLI, then automates Gmail, Drive, Sheets, Calendar, Docs, Chat and Tasks with ready-made recipes, persona bundles and security audits.

    2.2k GitHub stars~2.6k tokensUpdated 2 mo ago
    Auto-check: notes
  • HealthFit Health Advisors

    LeoYeAI/openclaw-master-skills

    Runs four advisor roles, a fitness coach, nutritionist, data analyst and TCM practitioner, to build a health profile and track workouts, diet and wellness over time.

    2.2k GitHub stars~4.4k tokensUpdated 2 mo ago
    Auto-check passed

Questions about Phy Test Data Factory

What does Phy Test Data Factory do?

Schema-driven test data factory generator. An agent skill from LeoYeAI/openclaw-master-skills. Phy Test Data Factory is an agent skill from LeoYeAI/openclaw-master-skills. Schema-driven test data factory generator.

When should I use Phy Test Data Factory?

Phy Test Data Factory fits situations like: generate test data; factory functions; fake data from schema; /test-data-factory.

How do I install Phy Test Data Factory in Claude Code?

Run `npx skills add LeoYeAI/openclaw-master-skills --skill phy-test-data-factory -a claude-code`. Or copy the skill folder (skills/phy-test-data-factory in LeoYeAI/openclaw-master-skills) into .claude/skills/phy-test-data-factory in your project. Claude Code loads it when a task matches its description.

How do I install Phy Test Data Factory in Codex?

Run `npx skills add LeoYeAI/openclaw-master-skills --skill phy-test-data-factory -a codex`. Or copy the skill folder (skills/phy-test-data-factory in LeoYeAI/openclaw-master-skills) into .agents/skills/phy-test-data-factory in your project. Codex loads it when a task matches its description.

Can I use Phy Test Data Factory in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add LeoYeAI/openclaw-master-skills --skill phy-test-data-factory -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/phy-test-data-factory, .gemini/skills/phy-test-data-factory, .github/skills/phy-test-data-factory and .opencode/skills/phy-test-data-factory in your project.

What does Phy Test Data Factory need to run?

Going by SKILL.md and its folder, Phy Test Data Factory needs the command-line tools its instructions call (pip, npm, node and python3). Our summary lists: Python 3; Node.js.

Does Phy Test Data Factory access the network?

SKILL.md contains no URLs. Its commands use pip and npm, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Phy Test Data Factory safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Phy Test Data Factory use?

Phy Test Data Factory is published under the Apache-2.0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Phy Test Data Factory use?

About 5.5k tokens (SKILL.md is roughly 22k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Phy Test Data Factory?

Skills that share tags, products or a category with Phy Test Data Factory: Django Filter Benchmark (saleor/saleor, 23k stars), Fastapi (ericrisco/rsc-harness, 174 stars), Pytest (mathiasertl/django-ca, 158 stars) and Dummy Dataset Generator (phuryn/pm-skills, 27k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Phy Test Data Factory?

LeoYeAI (a GitHub user) maintains it in LeoYeAI/openclaw-master-skills, which has 2,160 GitHub stars. The repository holds 1,235 skills in this directory. The repository was last updated on July 20, 2026.

Source: LeoYeAI/openclaw-master-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.