test-data-management

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
<objective> Create, maintain, and clean up test data that is deterministic, isolated, realistic, and safe. Good test data is the foundation of reliable tests -- without it, tests are either flaky (shared mutable state), unrealistic (hardcoded nonsense values), or dangerous (production PII in test environments). This skill delivers factories, fixtures, idempotent seeds, anonymization pipelines, and cleanup strategies that survive parallel execution. </objective>
<objective> 创建、维护和清理具有确定性、隔离性、真实性和安全性的测试数据。优质的测试数据是可靠测试的基础——没有它,测试要么不稳定(共享可变状态),要么不真实(硬编码的无意义值),要么存在风险(测试环境中包含生产环境的个人可识别信息PII)。本技能提供可支持并行执行的工厂、夹具、幂等种子数据、匿名化流水线和清理策略。 </objective>

Quick Route

快速指南

SituationGo to
Need fresh entity data with per-test overridesFactory Patterns →
references/factories.md
Mocking an API response or golden fileFixture Strategies →
references/factories.md
Copying production data anywhere non-prodData Anonymization
Populating a test DB / reference data idempotentlyDatabase Seeding →
references/seeding-and-synthetic.md
Cleaning up after tests / parallel isolationCleanup Strategies →
references/seeding-and-synthetic.md
Generating edge cases and boundary valuesSynthetic Data →
references/seeding-and-synthetic.md

场景查看内容
需要可按测试覆盖的全新实体数据工厂模式 →
references/factories.md
模拟API响应或基准文件夹具策略 →
references/factories.md
将生产数据复制到非生产环境数据匿名化
幂等填充测试数据库/参考数据数据库种子数据 →
references/seeding-and-synthetic.md
测试后清理/并行隔离清理策略 →
references/seeding-and-synthetic.md
生成边缘案例和边界值合成数据 →
references/seeding-and-synthetic.md

Discovery Questions

探索问题

Before designing a test data strategy, understand the current state. Check
.agents/qa-project-context.md
first -- if it exists, use it as the foundation and skip questions already answered there.
在设计测试数据策略之前,先了解当前状态。首先查看
.agents/qa-project-context.md
——如果存在,以此为基础并跳过已回答的问题。

Current Data Practices

当前数据实践

  • How is test data created today? (manually, scripts, copy of production, none)
  • Do tests share data or does each test create its own?
  • How is test data cleaned up? (truncate, rollback, manual, never)
  • Are there seed scripts? Are they idempotent?
  • 目前如何创建测试数据?(手动、脚本、生产数据副本、无)
  • 测试是共享数据还是每个测试创建自己的数据?
  • 如何清理测试数据?(截断、回滚、手动、从不清理)
  • 是否有种子脚本?它们是否具有幂等性?

Privacy and Compliance

隐私与合规

  • Does the product handle PII? (names, emails, addresses, phone numbers, SSNs)
  • Are there GDPR, HIPAA, PCI-DSS, or other data protection requirements?
  • Is production data ever used in test environments?
  • 产品是否处理个人可识别信息(PII)?(姓名、邮箱、地址、电话号码、社保号)
  • 是否有GDPR、HIPAA、PCI-DSS或其他数据保护要求?
  • 测试环境中是否曾使用生产数据?

Scale and Complexity

规模与复杂度

  • How large are the test datasets? (dozens of records, thousands, millions)
  • How complex are the data relationships? (simple CRUD, deep nested hierarchies, polymorphic)
  • Are there cross-service data dependencies? (microservices sharing data)

  • 测试数据集有多大?(数十条记录、数千条、数百万条)
  • 数据关系有多复杂?(简单CRUD、深度嵌套层级、多态)
  • 是否存在跨服务数据依赖?(微服务共享数据)

Core Principles

核心原则

1. Each Test Owns Its Data

1. 每个测试独立拥有其数据

Tests that rely on pre-existing shared data are fragile. When Test A modifies shared data, Test B breaks. Every test should create exactly the data it needs, verify against that data, and clean up after itself. This enables parallel execution and eliminates ordering dependencies.
依赖预先存在的共享数据的测试很脆弱。当测试A修改共享数据时,测试B会失败。每个测试都应创建其恰好需要的数据,针对该数据进行验证,并在自身执行完毕后清理数据。这支持并行执行并消除顺序依赖。

2. Factories Over Fixtures for Dynamic Data

2. 动态数据优先使用工厂而非夹具

Static fixtures (JSON/YAML files) are appropriate for reference data that does not change (country codes, currency lists). For entity data that tests create and manipulate (users, orders, products), use factory functions that generate fresh instances with sensible defaults and allow per-test overrides.
静态夹具(JSON/YAML文件)适用于不会更改的参考数据(国家代码、货币列表)。对于测试创建和操作的实体数据(用户、订单、产品),请使用工厂函数生成具有合理默认值的新实例,并允许按测试覆盖默认值。

3. Anonymize Production Data Before Use

3. 使用前先匿名化生产数据

Production databases contain the most realistic data, but they also contain real user information. Never copy production data to test environments without anonymization. Replace PII with synthetic equivalents while preserving data distributions and relationships.
生产数据库包含最真实的数据,但也包含真实用户信息。未经匿名化,切勿将生产数据复制到测试环境。用合成数据替换PII,同时保留数据分布和关系。

4. Deterministic Data Enables Reproducible Tests

4. 确定性数据实现可复现测试

Tests should produce the same results regardless of when or where they run. Avoid
Math.random()
,
Date.now()
, or auto-increment IDs in assertions. Use seeded random generators (
faker.seed(n)
), fixed timestamps, factory sequences, and -- when an ID must be a UUID you assert on -- a seeded
faker.string.uuid()
so it stays stable across runs.
无论何时何地运行,测试都应产生相同结果。在断言中避免使用
Math.random()
Date.now()
或自增ID。使用种子随机生成器(
faker.seed(n)
)、固定时间戳、工厂序列——当必须在断言中使用UUID时,使用种子化的
faker.string.uuid()
以确保在多次运行中保持稳定。

5. Minimize Data, Maximize Signal

5. 最小化数据,最大化信号

Create only the data each test needs. A test for user search does not need a complete user profile with billing address, payment method, and order history. Over-specified test data obscures the intent of the test and increases maintenance burden.

仅创建每个测试所需的数据。用户搜索测试不需要包含账单地址、支付方式和订单历史的完整用户资料。过度指定的测试数据会掩盖测试意图并增加维护负担。

Factory Patterns

工厂模式

Factories are functions that produce test data with sensible defaults, allowing individual tests to override only what matters for their scenario. Fishery (2.4.0) is the default for TypeScript, FactoryBot (6.6.0) for Ruby, factory-boy (3.3.3) for Python; all pair with faker (v10.4.0) for realistic field values.
See
references/factories.md
for the full Fishery (with associations and deterministic UUIDs), FactoryBot (User + Product
out_of_stock
/
discounted
traits), Factory Boy (
class Params
+
Trait
), and Playwright fixture implementations. The shape every factory follows:
  • Defaults + overrides
    Factory.define
    produces sensible defaults; tests pass overrides for the one field they care about (
    userFactory.build({ role: 'admin' })
    ).
  • Sequences for unique fields
    sequence
    (Fishery),
    sequence(:email)
    (FactoryBot),
    factory.Sequence
    (Factory Boy) — never hardcode IDs or emails.
  • Traits for variants — name common states (
    :admin
    ,
    :inactive
    ,
    out_of_stock
    ,
    discounted
    ) instead of spawning a fixture file per combination.
  • Associations — one factory builds another (an order builds its user), keeping referential structure without manual wiring.
工厂是生成具有合理默认值的测试数据的函数,允许单个测试仅覆盖其场景所需的内容。Fishery(2.4.0)是TypeScript的默认选择,FactoryBot(6.6.0)适用于Ruby,factory-boy(3.3.3)适用于Python;它们都与faker(v10.4.0)配合使用以生成真实的字段值。
查看
references/factories.md
获取完整的Fishery(含关联关系和确定性UUID)、FactoryBot(用户 + 产品
out_of_stock
/
discounted
特征)、Factory Boy(
class Params
+
Trait
)以及Playwright夹具实现。每个工厂遵循的结构:
  • 默认值 + 覆盖 ——
    Factory.define
    生成合理默认值;测试传递其关心的单个字段的覆盖值(
    userFactory.build({ role: 'admin' })
    )。
  • 唯一字段的序列 ——
    sequence
    (Fishery)、
    sequence(:email)
    (FactoryBot)、
    factory.Sequence
    (Factory Boy)——切勿硬编码ID或邮箱。
  • 变体特征 —— 为常见状态命名(
    :admin
    :inactive
    out_of_stock
    discounted
    ),而非为每种组合创建一个夹具文件。
  • 关联关系 —— 一个工厂构建另一个工厂的实例(订单构建其关联的用户),无需手动关联即可保持引用结构。

When to Use Factories vs Fixtures

工厂与夹具的使用场景对比

ScenarioFactoriesStatic Fixtures
Entity data that tests create/modifyYesNo
Reference data (countries, currencies, configs)NoYes
Data with many variations per testYesNo -- file explosion
Data with complex relationshipsYes -- associationsNo -- hard to maintain
API response mocksNoYes -- JSON fixtures
Snapshot/golden file comparisonsNoYes
Decision rule: If the data has a lifecycle (created, modified, deleted during tests), use a factory. If the data is read-only reference material, use a fixture file.

场景使用工厂使用静态夹具
测试创建/修改的实体数据
参考数据(国家、货币、配置)
每个测试有多种变体的数据否——会导致文件爆炸
具有复杂关系的数据是——支持关联否——难以维护
API响应模拟是——JSON夹具
快照/基准文件对比
决策规则:如果数据有生命周期(测试期间创建、修改、删除),请使用工厂。如果数据是只读参考资料,请使用夹具文件。

Fixture Strategies

夹具策略

Three fixture shapes, all in
references/factories.md
:
  • Static fixtures (JSON/YAML) — best for API response mocks (
    page.route
    +
    route.fulfill
    ), config data, and golden file comparisons.
  • Dynamic fixtures (Playwright)
    test.extend
    creates data via API before the test and deletes it after
    await use(...)
    . The standard per-test setup/teardown.
  • Fixture composition — combine factory-built data (
    userFactory.build()
    ,
    orderFactory.buildList(3)
    ) inside a single
    test.extend
    that seeds and cleans up in one step.

三种夹具形式,均在
references/factories.md
中:
  • 静态夹具(JSON/YAML) —— 最适合API响应模拟(
    page.route
    +
    route.fulfill
    )、配置数据和基准文件对比。
  • 动态夹具(Playwright) ——
    test.extend
    在测试前通过API创建数据,并在
    await use(...)
    后删除数据。这是标准的每测试前置/后置操作。
  • 夹具组合 —— 在单个
    test.extend
    中组合工厂生成的数据(
    userFactory.build()
    orderFactory.buildList(3)
    ),一步完成种子数据填充和清理。

Data Anonymization

数据匿名化

When production data is needed for realistic testing, anonymize it before use.
当需要生产数据进行真实测试时,请在使用前匿名化。

PII Masking Rules

PII掩码规则

Data TypeAnonymization MethodExample
EmailFaker email with original domain pattern
jane.doe@acme.com
->
user-7291@test.example.com
Full nameFaker name
Jane Doe
->
Alice Johnson
Phone numberFaker phone, preserve format
+1-555-123-4567
->
+1-555-987-6543
AddressFaker address, preserve country/region
123 Main St, NYC
->
456 Oak Ave, NYC
SSN/National IDTest pattern
123-45-6789
->
000-00-0001
Credit cardTest card numbers
4111-...
->
4242-4242-4242-4242
Date of birthShift by fixed offset
1990-03-15
->
1987-07-22
The anonymization pipeline -- seeded Faker for determinism, an in-memory lookup table, parent-records-first ordering, and a wrapping transaction -- is in
references/seeding-and-synthetic.md
(Anonymization with Faker.js, Referential Integrity During Anonymization). Anonymizing a user's email must also update that email everywhere it is referenced (orders, comments, audit logs); process parents first, children second, using the same lookup, all inside one transaction.
数据类型匿名化方法示例
邮箱使用Faker生成符合原始域名模式的邮箱
jane.doe@acme.com
->
user-7291@test.example.com
全名使用Faker生成姓名
Jane Doe
->
Alice Johnson
电话号码使用Faker生成电话号码,保留格式
+1-555-123-4567
->
+1-555-987-6543
地址使用Faker生成地址,保留国家/地区
123 Main St, NYC
->
456 Oak Ave, NYC
社保号/国家ID使用测试模式
123-45-6789
->
000-00-0001
信用卡使用测试卡号
4111-...
->
4242-4242-4242-4242
出生日期偏移固定时长
1990-03-15
->
1987-07-22
匿名化流水线——用于确定性的种子化Faker、内存查找表、父记录优先排序以及事务包装——位于
references/seeding-and-synthetic.md
(使用Faker.js进行匿名化、匿名化期间的引用完整性)。匿名化用户邮箱时,还必须更新所有引用该邮箱的位置(订单、评论、审计日志);先处理父记录,再处理子记录,使用相同的查找表,所有操作在一个事务内完成。

GDPR Compliance Checklist

GDPR合规检查清单

  • No real PII exists in any non-production environment
  • Anonymization is irreversible (no lookup table mapping back to originals is stored)
  • Anonymization preserves data distributions (age ranges, geographic spread) for realistic testing
  • Anonymized data cannot be re-identified through combination of quasi-identifiers
  • Data retention policies apply to test environments (auto-delete after N days)
  • The anonymization pipeline runs automatically, not manually (eliminates human error)

  • 任何非生产环境中均不存在真实PII
  • 匿名化是不可逆的(不存储映射回原始数据的查找表)
  • 匿名化保留数据分布(年龄范围、地理分布)以实现真实测试
  • 匿名化数据无法通过准标识符的组合重新识别
  • 数据保留策略适用于测试环境(N天后自动删除)
  • 匿名化流水线自动运行,无需手动操作(消除人为错误)

Database Seeding

数据库种子数据

Idempotent Seed Scripts

幂等种子脚本

Seed scripts must be safe to run multiple times without duplicating data. Use upsert --
INSERT ... ON CONFLICT (natural_key) DO UPDATE SET ...
-- keyed on a stable natural key, not the primary key. A
DELETE
-then-
INSERT
"reset" is not idempotent: it breaks foreign keys and reassigns serial IDs. See
references/seeding-and-synthetic.md
(Idempotent Seed Scripts) for the full
INSERT ... ON CONFLICT (code) DO UPDATE
countries/currencies example and the reasoning.
种子脚本必须可安全多次运行而不会重复数据。使用upsert——
INSERT ... ON CONFLICT (natural_key) DO UPDATE SET ...
——基于稳定的自然键而非主键。
DELETE
INSERT
的「重置」方式不具有幂等性:它会破坏外键并重新分配序列ID。查看
references/seeding-and-synthetic.md
(幂等种子脚本)获取完整的
INSERT ... ON CONFLICT (code) DO UPDATE
国家/货币示例及原理说明。

Database Branching (DB-as-a-Service)

数据库分支(数据库即服务)

If your prod DB lives on Neon, Supabase, or PlanetScale, branching can give a PR its own database instead of seeding from scratch -- but the providers differ on whether the branch carries data:
  • Neon Branching — copy-on-write Postgres branches in seconds, with data; ideal for ephemeral preview envs. The strongest "PR gets a real DB copy" story.
  • Supabase Branching
    supabase branches create pr-123
    clones schema and (optionally, from a backup) data; preview env points at the branch URL.
  • PlanetScale Branching — MySQL branches are schema-only by default (no data), so you still seed the branch. Note: PlanetScale removed its free Hobby tier (April 2024); MySQL now starts at ~$39/mo, Postgres ~$5/mo.
Pair with the Preview Environments pattern in
test-environments
.
Avoid: Snaplet (hosted) — shut down 31 Aug 2024; the team joined Supabase.
@snaplet/seed
lives on as
supabase-community/seed
(community-maintained, last meaningful release v0.98.0, July 2024, no feature work since). For new projects, prefer the DB-branching providers above plus factory-generated seeds.
如果你的生产数据库部署在NeonSupabasePlanetScale,分支功能可为PR提供独立数据库,无需从头填充种子数据——但各提供商的分支是否包含数据有所不同:
  • Neon分支 —— 秒级创建写时复制的Postgres分支,包含数据;非常适合临时预览环境。是「PR获得真实数据库副本」的最佳方案。
  • Supabase分支 ——
    supabase branches create pr-123
    克隆架构和(可选,从备份)数据;预览环境指向分支URL。
  • PlanetScale分支 —— MySQL分支默认仅包含架构(无数据),因此仍需为分支填充种子数据。注意:PlanetScale已取消免费Hobby套餐(2024年4月);MySQL现在起价约39美元/月,Postgres约5美元/月。
配合
test-environments
中的预览环境模式使用。
注意:避免使用Snaplet(托管服务) —— 已于2024年8月31日关闭;团队加入了Supabase。
@snaplet/seed
作为
supabase-community/seed
继续存在(社区维护,最后一次有意义的版本是v0.98.0, 2024年7月,此后无功能更新)。对于新项目,优先选择上述数据库分支提供商加工厂生成的种子数据。

Per-Test vs Per-Suite Data

每测试 vs 每套件数据

StrategyWhen to UseProsCons
Per-test setup/teardownTests that modify dataFull isolation, parallel-safeSlower, more setup code
Per-suite seedRead-only reference dataFast, simpleCannot be modified by tests
Per-worker seedPlaywright parallel workersBalances speed and isolationRequires worker-scoped fixtures
Global seedEnvironment bootstrapRuns once, sets up baselineMust be idempotent, shared state risk
For the worker-scoped fixture (
test.extend
with
{ scope: 'worker' }
) that powers per-worker seeding, see
references/factories.md
(Worker-Scoped Seeding).
策略使用场景优点缺点
每测试前置/后置操作修改数据的测试完全隔离,支持并行速度较慢,设置代码较多
每套件种子数据只读参考数据快速、简单测试无法修改数据
每Worker种子数据Playwright并行Worker平衡速度与隔离性需要Worker作用域的夹具
全局种子数据环境初始化仅运行一次,建立基线必须具有幂等性,存在共享状态风险
关于支持每Worker种子数据的Worker作用域夹具(
test.extend
搭配
{ scope: 'worker' }
),请查看
references/factories.md
(Worker作用域种子数据填充)。

Cleanup Strategies

清理策略

StrategyWhen to useSpeed
Transaction rollbackUnit/integration tests with direct DB accessFastest
Truncation (
TRUNCATE ... CASCADE
)
Resetting tables between suitesMedium
API-based cleanupE2E tests with no direct DB accessSlowest
Transaction rollback cannot clean up E2E tests -- the app opens its own DB connections, so a test-side transaction can't undo the app's writes; use API-based cleanup (delete in reverse creation order) there. All three implementations are in
references/seeding-and-synthetic.md
(Cleanup Strategies).

策略使用场景速度
事务回滚直接访问数据库的单元/集成测试最快
截断 (
TRUNCATE ... CASCADE
)
套件间重置表中等
基于API的清理无直接数据库访问的端到端测试最慢
事务回滚无法清理端到端测试——应用会打开自己的数据库连接,因此测试端的事务无法撤销应用的写入;此时需使用基于API的清理(按创建逆序删除)。三种实现均位于
references/seeding-and-synthetic.md
(清理策略)。

Synthetic Data Generation

合成数据生成

Factories should make it easy to generate edge cases and boundary values without hand-writing them per test. The reusable arrays and helpers --
edgeCaseStrings
(empty, whitespace, very long, XSS, SQL injection, null/control chars, RTL override),
edgeCaseDates
, and
boundaryValues(min, max)
driving a
test.each
-- are in
references/seeding-and-synthetic.md
(Synthetic Data Generation).

工厂应便于生成边缘案例和边界值,无需为每个测试手动编写。可复用的数组和助手——
edgeCaseStrings
(空值、空白字符、超长字符串、XSS、SQL注入、空/控制字符、RTL覆盖)、
edgeCaseDates
boundaryValues(min, max)
驱动
test.each
——位于
references/seeding-and-synthetic.md
(合成数据生成)。

Anti-Patterns

反模式

Shared Mutable Test Data

共享可变测试数据

Multiple tests reading and writing the same database rows. Test A creates a user, Test B modifies it, Test C asserts on the original state and fails. Fix by having each test create its own data through factories.
多个测试读写同一数据库行。测试A创建用户,测试B修改该用户,测试C断言原始状态并失败。修复方法是让每个测试通过工厂创建自己的数据。

Production Data Without Anonymization

未匿名化的生产数据

Copying the production database to staging for "realistic testing." This violates GDPR, risks data breaches in less-secured environments, and creates compliance liability. Always anonymize before use, or generate synthetic data that matches production distributions.
将生产数据库复制到预发布环境进行「真实测试」。这违反GDPR,在安全性较低的环境中存在数据泄露风险,并产生合规责任。使用前务必匿名化,或生成匹配生产数据分布的合成数据。

Non-Deterministic Data

非确定性数据

Using
Math.random()
or
Date.now()
in test data creation without seeding. Tests pass on Monday and fail on Tuesday because the random name generated happens to exceed a field length limit. Use seeded Faker instances and fixed timestamps.
在测试数据创建中使用
Math.random()
Date.now()
而不设置种子。周一测试通过,周二测试失败,因为生成的随机姓名恰好超过字段长度限制。使用种子化Faker实例和固定时间戳。

No Cleanup Strategy

无清理策略

Tests that create data and never clean it up. The test database grows until it affects performance, or stale data causes false positives in other tests. Every data creation must have a corresponding cleanup.
创建数据后从不清理的测试。测试数据库不断增长直至影响性能,或陈旧数据导致其他测试出现误报。每次数据创建都必须有对应的清理操作。

Fixture File Explosion

夹具文件爆炸

Creating a separate JSON fixture file for every test variation. Instead of
user-admin.json
,
user-inactive.json
,
user-admin-inactive.json
, use a factory with traits. Fixtures should be reserved for static reference data and API response mocks.
为每个测试变体创建单独的JSON夹具文件。不要创建
user-admin.json
user-inactive.json
user-admin-inactive.json
,而是使用带特征的工厂。夹具应仅用于静态参考数据和API响应模拟。

Over-Specified Test Data

过度指定测试数据

Creating a complete user object with 30 fields when the test only cares about
role
. This obscures intent and makes tests brittle. Factories with sensible defaults solve this: override only what the test cares about.
当测试仅关心
role
字段时,创建包含30个字段的完整用户对象。这会掩盖测试意图并使测试变得脆弱。具有合理默认值的工厂可解决此问题:仅覆盖测试关心的内容。

Hard-Coded IDs

硬编码ID

Using
userId: '1'
in tests. This couples tests to database state and breaks when running in parallel (ID collision) or against a database with existing data. Use factory sequences or seeded UUIDs (see Core Principle 4).

在测试中使用
userId: '1'
。这会将测试与数据库状态耦合,在并行运行(ID冲突)或针对已有数据的数据库运行时会失败。使用工厂序列或种子化UUID(参见核心原则4)。

Verification

验证

Prove the data layer is deterministic, isolated, and PII-free, smallest check first:
  1. Seeds are idempotent — run the seed twice back-to-back and diff the row counts:
    psql -c "SELECT count(*) FROM countries" && <seed> && psql -c "SELECT count(*) FROM countries"
    returns the same number both times and exits 0. A growing count means a missing
    ON CONFLICT
    .
  2. No shared mutable state — run the suite under parallelism and randomized order:
    npx playwright test --workers=4
    (or
    pytest -n auto -p randomly
    ) stays green. A failure that only appears here is an ordering or shared-data dependency.
  3. Determinism holds — run the same data-generating test twice; with
    faker.seed(n)
    set, generated names/IDs/UUIDs match across runs. If they drift, an unseeded Faker call or
    Date.now()
    /
    crypto.randomUUID()
    leaked in.
  4. No real PII
    grep -rE '@(gmail|outlook|yahoo)\.com|[0-9]{3}-[0-9]{2}-[0-9]{4}' tests/ fixtures/
    returns nothing (real-looking emails and SSNs). Anything it finds is an anonymization gap.
  5. Cleanup returns to baseline — snapshot row counts before the suite, run it, snapshot again: the test DB is back to baseline with no orphaned records.

证明数据层具有确定性、隔离性且无PII,从最小检查开始:
  1. 种子数据具有幂等性 —— 连续运行两次种子脚本并对比行数:
    psql -c "SELECT count(*) FROM countries" && <seed> && psql -c "SELECT count(*) FROM countries"
    两次返回相同数字且退出码为0。行数增加意味着缺少
    ON CONFLICT
  2. 无共享可变状态 —— 在并行和随机顺序下运行套件:
    npx playwright test --workers=4
    (或
    pytest -n auto -p randomly
    )保持通过。仅在此场景下出现的失败是顺序或共享数据依赖问题。
  3. 确定性保持 —— 运行两次相同的数据生成测试;设置
    faker.seed(n)
    后,生成的姓名/ID/UUID在多次运行中一致。如果出现偏差,说明存在未设置种子的Faker调用或
    Date.now()
    /
    crypto.randomUUID()
    泄露。
  4. 无真实PII ——
    grep -rE '@(gmail|outlook|yahoo)\.com|[0-9]{3}-[0-9]{2}-[0-9]{4}' tests/ fixtures/
    无返回结果(真实邮箱和社保号)。任何匹配结果都是匿名化漏洞。
  5. 清理后恢复基线 —— 套件运行前快照行数,运行后再次快照:测试数据库恢复到基线状态,无孤立记录。

Done When

完成标准

  • Every entity type the suite creates has a factory or fixture (no inline ad-hoc object literals in tests for shared entities -- grep the test dir for hand-built fixtures and confirm none remain).
  • Test data is isolated per test -- the suite passes with parallelism on (
    --workers=N
    /
    pytest -n auto
    ) and under randomized order (
    --shuffle
    /
    -p randomly
    ), proving no shared mutable state or ordering dependency.
  • Seed scripts are idempotent -- running the seed twice in a row produces the same row count and exits 0; the CI job runs them with no manual intervention.
  • No real PII used in test fixtures -- all sensitive data anonymized or synthetic (grep for production domains / real-looking SSNs returns nothing).
  • Data cleanup verified -- row counts in the test DB return to baseline after the suite (no orphaned records accumulate across runs).

  • 套件创建的每个实体类型都有工厂或夹具(测试目录中没有用于共享实体的内联临时对象字面量——搜索测试目录中的手动构建夹具并确认不存在)。
  • 测试数据按测试隔离——套件在并行模式开启(
    --workers=N
    /
    pytest -n auto
    随机顺序(
    --shuffle
    /
    -p randomly
    )下通过,证明无共享可变状态或顺序依赖。
  • 种子脚本具有幂等性——连续运行两次产生相同行数且退出码为0;CI作业自动运行它们,无需手动干预。
  • 测试夹具中无真实PII——所有敏感数据均已匿名化或为合成数据(搜索生产域名/真实社保号无结果)。
  • 数据清理已验证——套件运行后测试数据库行数恢复到基线(无孤立记录累积)。

Reference Files (in
references/
)

参考文件(位于
references/

  • factories.md — Full Fishery (associations, deterministic UUIDs), FactoryBot (User + Product traits), Factory Boy (
    Params
    /
    Trait
    ), static/dynamic/composed Playwright fixtures, and the worker-scoped seeding fixture.
  • seeding-and-synthetic.md — Idempotent
    ON CONFLICT
    seed script, Faker.js anonymization + referential-integrity pipeline, cleanup strategies (rollback / truncate / API), and synthetic edge-case + boundary-value generators.
  • factories.md —— 完整的Fishery(关联关系、确定性UUID)、FactoryBot(用户 + 产品特征)、Factory Boy(
    Params
    /
    Trait
    )、静态/动态/组合Playwright夹具,以及Worker作用域种子数据填充夹具。
  • seeding-and-synthetic.md —— 幂等
    ON CONFLICT
    种子脚本、Faker.js匿名化 + 引用完整性流水线、清理策略(回滚 / 截断 / API),以及合成边缘案例 + 边界值生成器。

Related Skills

相关技能

  • unit-testing -- Unit tests are the primary consumer of factory-generated data; this skill provides the data layer.
  • api-testing -- API tests use both factories (for request bodies) and fixtures (for mocked responses).
  • playwright-automation -- E2E tests need test data seeded via API or fixtures before browser interaction.
  • test-reliability -- Deterministic test data eliminates a major source of test flakiness.
  • test-environments -- Owns environment provisioning and database-branching strategy (Neon, Supabase, PlanetScale) for preview envs; this skill owns the data that fills them.
  • database-testing -- Migration testing, data-integrity assertions, and Testcontainers for the database layer specifically -- go there to test the DB, come here to populate it.
  • ci-cd-integration -- Database seeding and cleanup must be integrated into CI pipeline stages.
  • unit-testing —— 单元测试是工厂生成数据的主要使用者;本技能提供数据层支持。
  • api-testing —— API测试同时使用工厂(用于请求体)和夹具(用于模拟响应)。
  • playwright-automation —— 端到端测试需要在浏览器交互前通过API或夹具填充测试数据。
  • test-reliability —— 确定性测试数据消除了测试不稳定的主要来源之一。
  • test-environments —— 负责预览环境的环境配置和数据库分支策略(Neon、Supabase、PlanetScale);本技能负责填充环境中的数据。
  • database-testing —— 迁移测试、数据完整性断言以及针对数据库层的Testcontainers——测试数据库请前往该技能,填充数据请使用本技能。
  • ci-cd-integration —— 数据库种子数据填充和清理必须集成到CI流水线阶段。