mcpField
T
test-data-management

test-data-management

github.com/petrkindlmann测试与质量2221.4k 次安装6 天前更新
代码仓库

关于 test-data-management

面向测试工程师的测试数据管理技能,涵盖数据工厂、固定数据、播种、清理和匿名化。它强调每个测试独立拥有数据,以支持确定性、并行执行和隐私保护。

主要功能

  1. 01使用工厂生成可覆盖的数据
  2. 02用固定数据模拟响应与基准文件
  3. 03创建幂等数据库播种
  4. 04匿名化生产数据中的个人信息
  5. 05隔离测试数据并清理状态
  6. 06生成合成边界与极端数据

适用场景

  1. 01为每个测试创建独立实体数据
  2. 02准备 API 模拟响应与参考数据
  3. 03在非生产环境使用匿名化数据
  4. 04并行执行测试并清理其数据

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/petrkindlmann/qa-skills --skill test-data-management

安装后在 Claude Code 中输入/test-data-management确认已加载。

附带文件references/factories.mdreferences/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

调研问题

设计测试数据策略前,先了解当前情况。首先检查 .agents/qa-project-context.md——如果该文件存在,请以其为基础,并跳过其中已有答案的问题。

当前数据实践
  • 目前如何创建测试数据?(手动、脚本、复制生产数据、没有)
  • 测试是否共享数据,还是每个测试都自行创建数据?
  • 如何清理测试数据?(清空表、回滚、手动、从不)
  • 是否有种子脚本?这些脚本是否幂等?
隐私与合规
  • 产品是否处理个人身份信息?(姓名、电子邮件、地址、电话号码、SSN)
  • 是否有 GDPR、HIPAA、PCI-DSS 或其他数据保护要求?
  • 是否曾在测试环境中使用生产数据?
规模与复杂度
  • 测试数据集有多大?(数十条、数千条、数百万条记录)
  • 数据关系有多复杂?(简单的 CRUD、深层嵌套层级、多态关系)
  • 是否存在跨服务的数据依赖?(共享数据的微服务)

核心原则

1. 每个测试都拥有自己的数据

依赖预先存在的共享数据会让测试变得脆弱。当测试 A 修改共享数据时,测试 B 就会失败。每个测试都应只创建所需的数据,使用这些数据进行验证,并在测试后自行清理。这样可以支持并行执行,并消除对执行顺序的依赖。

2. 动态数据优先使用工厂,而非固定数据

静态固定数据(JSON/YAML 文件)适用于不会变化的参考数据(国家代码、货币列表)。对于测试需要创建和操作的实体数据(用户、订单、产品),应使用工厂函数生成具有合理默认值的新实例,并允许为每个测试覆盖相应的值。

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

生产数据库包含最贴近真实的数据,但也包含真实用户信息。未经匿名化,绝不要将生产数据复制到测试环境。将个人身份信息替换为合成数据,同时保留数据分布和关系。

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

无论测试何时、何地运行,都应产生相同结果。避免在断言中使用 Math.random()、Date.now() 或自增 ID。使用带种子的随机生成器(faker.seed(n))、固定时间戳、工厂序列;如果断言中必须使用 UUID,则使用带种子的 faker.string.uuid(),使其在不同运行中保持稳定。

5. 减少数据,增强信号

只创建每个测试所需的数据。测试用户搜索时,不需要完整的用户档案,包括账单地址、支付方式和订单历史。过度指定测试数据会模糊测试意图,并增加维护负担。


工厂模式

工厂是生成测试数据的函数,带有合理的默认值,让各个测试只需覆盖其场景中重要的数据。TypeScript 默认使用 Fishery(2.4.0),Ruby 使用 FactoryBot(6.6.0),Python 使用 factory-boy(3.3.3);它们都搭配 faker(v10.4.0),生成逼真的字段值。

完整的 Fishery(含关联和确定性 UUID)、FactoryBot(User + Product 的 out_of_stock/discounted traits)、Factory Boy(class Params + Trait)和 Playwright fixture 实现,请参阅 references/factories.md。所有工厂都遵循以下模式:

  • 默认值 + 覆盖项 — Factory.define 生成合理的默认值;测试只需传入所关注字段的覆盖值(userFactory.build({ role: 'admin' }))。
  • 为唯一字段设置序列 — sequence(Fishery)、sequence(:email)(FactoryBot)、factory.Sequence(Factory Boy)——绝不硬编码 ID 或电子邮件地址。
  • 用 traits 表示变体 — 为常见状态命名(:admin、:inactive、out_of_stock、discounted),而不是为每种组合单独创建 fixture 文件。
  • 关联 — 一个工厂构建另一个工厂(订单构建其用户),无需手动连接,同时保持引用结构。
何时使用工厂而非 fixture
场景工厂静态 fixture
测试创建或修改的实体数据是否
参考数据(国家、货币、配置)否是
每个测试中有许多变体的数据是否——文件数量会激增
关系复杂的数据是——使用关联否——难以维护
API 响应模拟否是——JSON fixture
快照/黄金文件对比否是

判断规则: 如果数据有生命周期(在测试期间创建、修改、删除),就使用工厂。如果数据是只读的参考资料,就使用 fixture 文件。


Fixture 策略

references/factories.md 中介绍了三种 fixture 形式:

  • 静态 fixture(JSON/YAML) — 最适用于 API 响应模拟(page.route + route.fulfill)、配置数据和黄金文件对比。
  • 动态 fixture(Playwright) — test.extend 在测试前通过 API 创建数据,并在 await use(...) 后删除数据。这是标准的单测试设置/清理方式。
  • Fixture 组合 — 在单个 test.extend 中组合由工厂构建的数据(userFactory.build()、orderFactory.buildList(3)),在一个步骤中完成数据填充和清理。

数据匿名化

当需要使用生产数据进行逼真的测试时,应先对其进行匿名化。

PII 遮蔽规则
数据类型匿名化方法示例
电子邮件使用 Faker 生成符合原域名模式的电子邮件[email protected] -> [email protected]
全名Faker 姓名Jane Doe -> Alice Johnson
电话号码使用 Faker 生成电话,保留格式+1-555-123-4567 -> +1-555-987-6543
地址使用 Faker 生成地址,保留国家/地区123 Main St, NYC -> 456 Oak Ave, NYC
SSN/国家身份号码测试格式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 合规检查清单
  • 任何非生产环境中都不存在真实的 PII
  • 匿名化不可逆(不存储可映射回原始数据的查找表)
  • 匿名化保留数据分布(年龄范围、地理分布),以便进行真实测试
  • 无法通过组合准标识符重新识别匿名化数据
  • 数据保留政策适用于测试环境(N 天后自动删除)
  • 匿名化流水线自动运行,而非手动执行(避免人为错误)

数据库播种

幂等的播种脚本

播种脚本必须支持安全地重复运行,而不产生重复数据。使用 upsert——INSERT ... ON CONFLICT (natural_key) DO UPDATE SET ...——并以稳定的自然键而非主键作为依据。先 DELETE 再 INSERT 的“重置”操作不具备幂等性:它会破坏外键关系,并重新分配序列 ID。完整的 INSERT ... ON CONFLICT (code) DO UPDATE 国家/货币示例及相关原因,请参见 references/seeding-and-synthetic.md(幂等的播种脚本)。

数据库分支(DB 即服务)

如果你的生产数据库托管在 Neon、Supabase 或 PlanetScale 上,分支功能可以为 PR 提供独立数据库,而不必从头播种——但各服务商在分支是否包含数据方面有所不同:

  • Neon Branching — 几秒内即可创建写时复制的 Postgres 分支,并包含数据;非常适合临时预览环境。这是“PR 获得真实数据库副本”最有力的方案。
  • Supabase Branching — supabase branches create pr-123 会克隆架构,并可选择从备份中克隆数据;预览环境指向分支 URL。
  • PlanetScale Branching — MySQL 分支默认仅包含架构(不含数据),因此仍需为分支播种。注意:PlanetScale 已于 2024 年 4 月移除免费的 Hobby 套餐;MySQL 现价约为每月 39 美元起,Postgres 约为每月 5 美元起。

结合 test-environments 中的预览环境模式使用。

避免使用:Snaplet(托管版) — 已于 2024 年 8 月 31 日停止服务;团队已加入 Supabase。@snaplet/seed 以 supabase-community/seed 的形式继续维护(由社区维护,最近一次有实质意义的发布为 v0.98.0, 时间为 2024 年 7 月,此后没有功能开发)。对于新项目,优先使用上述数据库分支服务商 以及由工厂生成的播种数据。

按测试或按测试套件准备数据
策略适用场景优点缺点
按测试设置/清理会修改数据的测试完全隔离,可安全并行速度较慢,需要编写更多设置代码
按测试套件播种只读参考数据快速、简单测试无法修改数据
按工作进程播种Playwright 并行工作进程兼顾速度与隔离需要工作进程作用域的 fixture
全局播种环境初始化只运行一次,设置基线必须具备幂等性,有共享状态风险

有关支持按工作进程播种的工作进程作用域 fixture(使用 { scope: 'worker' } 的 test.extend),请参见 references/factories.md(工作进程作用域播种)。

清理策略
策略适用场景速度
事务回滚可直接访问数据库的单元/集成测试最快
截断(TRUNCATE ... CASCADE)在测试套件之间重置表中等
基于 API 的清理无法直接访问数据库的 E2E 测试最慢

事务回滚无法清理 E2E 测试——应用会自行打开数据库连接,因此测试端的事务无法撤销应用的写入;这类测试应使用基于 API 的清理(按创建顺序的逆序删除)。三种实现均见 references/seeding-and-synthetic.md(清理策略)。

合成数据生成

工厂应能轻松生成边界情况和边界值,无需在每个测试中手动编写。可复用的数组和辅助函数——edgeCaseStrings(空字符串、空白、超长字符串、XSS、SQL 注入、空值/控制字符、RTL 覆盖字符)、edgeCaseDates,以及通过 test.each 驱动测试的 boundaryValues(min, max)——位于 references/seeding-and-synthetic.md(合成数据生成)。


反模式

共享的可变测试数据

多个测试读取和写入相同的数据库行。测试 A 创建用户,测试 B 修改用户,测试 C 断言原始状态并失败。解决方法是让每个测试通过工厂创建自己的数据。

未匿名化的生产数据

将生产数据库复制到预发布环境以进行“逼真测试”。这违反 GDPR,会在安全性较低的环境中造成数据泄露风险,并带来合规责任。使用前务必进行匿名化,或生成符合生产数据分布的合成数据。

非确定性数据

创建测试数据时使用 Math.random() 或 Date.now(),却没有设置种子。测试周一通过,周二却失败,因为随机生成的名称恰好超过了字段长度限制。使用带种子的 Faker 实例和固定时间戳。

没有清理策略

测试创建数据后从不清理。测试数据库不断增长,直到影响性能;或者过期数据导致其他测试误报。每次创建数据都必须有相应的清理操作。

夹具文件泛滥

为每种测试变体都创建单独的 JSON 夹具文件。不要使用 user-admin.json、user-inactive.json、user-admin-inactive.json,而应使用带特征的工厂。夹具应仅用于静态参考数据和 API 响应模拟。

测试数据指定过多

测试只关注 role,却创建包含 30 个字段的完整用户对象。这会模糊测试意图,并让测试变得脆弱。具有合理默认值的工厂可以解决这个问题:只覆盖测试关注的内容。

硬编码 ID

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


验证

证明数据层具有确定性、相互隔离且不含个人身份信息(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/ 不应返回任何内容(真实形式的邮箱和 SSN)。任何匹配结果都表明存在匿名化缺口。
  5. 清理后恢复到基线——在测试套件运行前后分别记录行数:测试 DB 应恢复到基线,不留下孤立记录。

完成标准

  • 套件创建的每种实体类型都有工厂或 fixture(测试中不为共享实体内联临时编写对象字面量——在测试目录中搜索手工构建的 fixture,并确认没有遗漏)。
  • 每个测试的数据彼此隔离——套件在启用并行(--workers=N / pytest -n auto)以及随机顺序(--shuffle / -p randomly)下均能通过,证明不存在共享可变状态或顺序依赖。
  • 种子脚本具有幂等性——连续运行两次种子脚本会生成相同的行数并以状态码 0 退出;CI 作业会自动运行这些脚本。
  • 测试 fixture 中不使用真实个人身份信息(PII)——所有敏感数据均已匿名化或为合成数据(搜索生产环境域名 / 看起来真实的 SSN 时没有任何匹配结果)。
  • 已验证数据清理——测试套件运行后,测试数据库中的行数会恢复到基线(多次运行不会累积孤立记录)。

参考文件(位于 references/ 中)

  • factories.md — 完整介绍 Fishery(关联、确定性 UUID)、FactoryBot(User + Product traits)、Factory Boy(Params/Trait)、静态 / 动态 / 组合式 Playwright fixture,以及 worker 作用域的种子 fixture。
  • seeding-and-synthetic.md — 幂等的 ON CONFLICT 种子脚本、Faker.js 匿名化 + 参照完整性流水线、清理策略(回滚 / 截断 / API),以及合成边界情况和边界值生成器。

相关技能

  • unit-testing -- 单元测试是使用工厂生成数据的主要场景;此技能提供数据层。
  • api-testing -- API 测试同时使用工厂(生成请求体)和 fixture(模拟响应)。
  • playwright-automation -- E2E 测试需要在浏览器交互前通过 API 或 fixture 填充测试数据。
  • test-reliability -- 确定性测试数据可消除测试不稳定的一个主要来源。
  • test-environments -- 负责预览环境的环境配置和数据库分支策略(Neon、Supabase、PlanetScale);此技能负责填充这些环境的数据。
  • database-testing -- 专门针对数据库层的迁移测试、数据完整性断言和 Testcontainers——测试数据库请使用该技能,填充数据库则使用此技能。
  • ci-cd-integration -- 数据库种子和清理必须集成到 CI 流水线阶段中。

评论

支持 Markdown