mcpField
T
test-quality

test-quality

github.com/danielteles测试与质量346 次安装9 周前更新
代码仓库

关于 test-quality

test-quality 是与框架无关的工程技能,用于编写、评审、排查和刻画自动化测试。其规则聚焦可观察行为、明确断言、可维护的测试数据、受控替身及确定性执行。

主要功能

  1. 01编写、评审和排查测试
  2. 02断言可观察行为
  3. 03清晰组织并命名测试
  4. 04构建可维护的测试数据
  5. 05控制替身与测试确定性

适用场景

  1. 01为变更代码添加测试
  2. 02评审拉取请求中的测试
  3. 03修复脆弱或不稳定的测试
  4. 04重构前刻画现有行为

安装

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

$npx skills add https://github.com/danielteles/awesome-agent-skills --skill test-quality

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
builder.template.ts
references/
assertions.md
behavior-not-implementation.md
coverage.md
determinism.md
structure-and-naming.md
test-data.md
test-doubles.md
worked-example.md

详细介绍

测试质量 — 工程技能

与框架无关的标准,用于判断单个自动化测试是否值得保留:它断言什么、如何命名和组织、模拟什么,以及每次运行的结果是否一致。这些规则适用于任何测试运行器(Vitest、Jest、node:test)和任何框架;示例使用 TypeScript。

基于。 core-typescript(测试代码也是代码)、architecture-and-design(用于测试套件的策略,如测试金字塔、单元测试与集成测试),以及 react / angular / vue(用于渲染和查询组件的具体方法)。只有当任务涉及相应层面时才加载同级技能;如果未加载,请运用通用知识处理该层面,不要因此阻塞任务。

此 SKILL.md 内容完整独立:以下 规则集 是完整且可执行的规则清单。每个 references/<topic>.md 都包含该组规则的理由及 ❌ / ✅ 代码示例,references/worked-example.md 则提供完整的评审过程;运行环境允许时,可打开这些文件深入了解。


如何使用此技能

选择与任务匹配的模式,并按顺序执行步骤。

模式步骤
编写 — 为新增或修改的代码添加测试1. 对每种公开行为,命名场景并写明预期结果(structure-and-naming)。2. 通过公开 API 准备测试;一次调用完成操作;对可观察结果进行断言(behavior-not-implementation、assertions)。3. 使用构造器创建输入;只模拟 test-doubles 允许模拟的内容。4. 新增的每个测试都先运行一次并确认失败,再信任其通过结果;可以针对尚未修复的代码运行,也可以故意破坏一行代码。5. 将规则集作为检查清单逐项核对。交接前修复每一项未通过的问题。
评审 — 检查拉取请求中的测试1. 根据规则集检查测试差异。2. 对每项未通过的问题,按照下方输出格式写一条发现。3. 按顺序排列发现:先列 must-fix,再列 consider。4. 如果没有问题,用一行说明即可。不要臆造发现。
分类处理 — 修复薄弱、脆弱或不稳定的测试1. 指出问题所在:断言内部实现、没有实际断言、依赖执行顺序、结果非确定(determinism)。2. 修改测试,而非被测代码——除非测试发现了真实缺陷。3. 立即隔离不稳定测试;在当前迭代内修复,不要靠 CI 重试。
刻画 — 修改未经测试的代码前为其添加测试1. 编写测试,锁定代码当前可观察到的行为,包括各种特例——暂时不要修复缺陷。2. 在代码未改动时运行测试,确认全部通过;这就是安全网。3. 在安全网的保护下重构或修复;只有在你有意改变相应行为时,才更新刻画测试。
输出格式

每行写一条发现:

<severity> · <topic> · <file>:<line> — <what is wrong>. <the fix as an action>.
  • <severity> 为 must-fix(违反本技能规则)或 consider(虽然安全,但规则更倾向于另一种形式)。
  • <topic> 为规则集中的主题标识(assertions、test-doubles、determinism 等)。
什么样的测试值得保留

从四个方面评估每个测试,这些方面彼此权衡:

  • 回归保护 — 当真实行为遭到破坏时,测试会失败。
  • 重构适应性 — 内部实现变化但行为不变时,测试仍能通过。
  • 快速反馈 — 测试在毫秒内运行,因此每次保存时都能运行整个测试套件。
  • 可维护性 — 后续读者能看懂测试,并以较低成本进行修改。

在其中两个方面得分较低的测试就是负担。断言实现细节会牺牲重构适应性;真实 I/O 会牺牲快速反馈,且常常损害保护能力(导致不稳定测试);庞大的共享测试夹具会牺牲可维护性。以下每条规则都旨在保护这四个方面。

适用于所有模式的规则
  • 执行规则时,指出所依据的规则集主题。
  • 说明原因,而不只是说明规则。“即使 total() 拒绝,测试也会通过”胜过“等待 Promise”。
  • 指出规则和所做的更改;不要默默改写作者的测试。
  • 测试的目的是捕捉用户会感受到的回归。如果测试会因重命名而失败,却永远不会因行为变化而失败,那么它是负担,而非资产——请明确指出。
  • 当测试与代码不一致时,先查明谁是对的,再决定是否修改。

规则集

behavior-not-implementation → references/behavior-not-implementation.md
  • 测试断言可观察到的输出——返回值、渲染结果、已发布的消息、已持久化的记录——绝不针对私有字段或内部步骤。
  • 不得将协作者被调用的次数或调用参数作为检查调用效果的替代手段来断言,除非调用本身就是契约的一部分(例如分析事件、发送电子邮件)。
  • 测试只引用单元的公共 API;重命名私有辅助函数或调整内部步骤顺序不会导致测试失败。
  • 不得对被测系统进行间谍监视或部分模拟——应运行其真实代码。
  • Arrange 通过公共构造函数、工厂或 API 设置状态——不得触及内部实现。
  • 测试在保持行为不变的重构后仍能通过,并且会在行为改变时失败。
  • 不得只测试你不拥有的框架、库或语言特性——应在自己的边界上测试你对它的用法,而不是测试 React 是否会渲染,或 Array.map 是否会映射。
  • 被测单元应是一个行为单元,而不是单个类——协作者不会仅仅因为位于另一个文件中就被替换为测试替身。除非 test-doubles 有理由使用假对象,否则应运行真实代码。
  • 应通过公共 API 调用私有方法。如果它足够复杂,值得单独测试,就应将其提取为独立单元——而不是从后门测试。
assertions → references/assertions.md
  • 每项测试至少有一个断言;“不会抛出异常”的测试应明确写出这一点(expect(fn).not.toThrow())。
  • 每项测试只验证一种行为——多个 expect 没问题,只要它们描述的是同一个结果,而非互不相关的结果。
  • 使用具体的匹配器:用 toEqual(3) 代替 toBeTruthy();用 toThrow(SpecificError) 代替 toThrow();内容重要时应断言内容,而不仅仅是长度。
  • 断言应检查完整的相关结果,而不是只检查其中一个方便的字段。
  • 只有当顺序属于契约的一部分时,才将集合按有序列表进行比较;否则应先排序、作为集合比较,或使用 arrayContaining 检查。
  • 不得断言测试使用与被测代码相同的逻辑计算出的值——应使用手工计算的字面值。
  • 错误路径应断言错误类型或消息,而不只是断言发生了错误——使用 toThrow(SpecificError) / .rejects,绝不能使用在没有抛出任何错误时也会通过的 try/catch。
  • 异步测试应 await 结果,并在其完成后断言;应使用 await expect(...).rejects 检查拒绝。不得在 Promise 解决前运行断言。
  • 快照应简短、稳定,并在每次更改时经过审查——绝不能未经阅读就接受大型自动生成的内容。短值使用内联快照没问题;序列化的组件树不算断言。
structure-and-naming → references/structure-and-naming.md
  • 测试名称描述场景和预期结果(“空购物车返回 0”),而不是方法名称(“test getTotal”)。
  • Arrange / act / assert 三个步骤在视觉上清晰区分;act 步骤只有一次调用。
  • 测试主体中没有生产逻辑——没有与实现逻辑相仿的 if / for / switch / 算术运算。
  • 重复用例采用数据驱动表格(it.each);每个测试只针对一个失败原因。
  • beforeEach 仅包含文件中每个测试都需要的设置;特定于某个场景的内容留在测试中。
  • 不依赖执行顺序或上一个测试遗留的状态。
  • 不提交 .only / fit / fdescribe;使用 .skip / xit 时,必须在注释中注明已跟踪的问题单。
test-data → references/test-data.md
  • 使用工厂或构建器创建对象,并填入合理的默认值;测试只设置正在测试的字段。请从 assets/builder.template.ts 开始。
  • 断言所依赖的值直接展示在测试中,而不是藏在共享 fixture 里。
  • 不使用供许多测试以不同且互相冲突的方式依赖的大型共享 fixture。
  • 随机数据需设定种子,并在失败时打印;否则使用固定且有意义的字面值。
  • 不同角色使用不同的值——id 和 quantity 不能都为 1。
test-doubles → references/test-doubles.md
  • 只有在真实协作者运行缓慢、非确定性、有副作用或尚不存在时,才用测试替身替代它。
  • 在边界处对网络进行 stub(使用 MSW、fake server),而不是 mock 自己的模块。
  • 对许多测试都会使用的协作者,优先使用 fake(可运行的内存实现),而不是带有脚本化预期的 mock。
  • 手写 fake 需通过同时针对 fake 和真实实现运行的契约测试进行验证,否则 fake 会逐渐偏离真实实现,导致测试套件通过而生产环境出错。
  • 绝不 mock 被测类型。
  • stub 返回符合协作者契约的真实值,而不是碰巧能用的 undefined。
  • 在测试之间重置 mock;不得让 stub 泄漏到下一个测试或文件中。
  • 时间、随机性、文件系统和环境变量需通过注入或 fake 控制,不要直接访问。
determinism → references/determinism.md
  • 单元测试不进行真实 I/O——不访问实时网络、数据库、磁盘或系统时钟。如果某种行为确实需要这些资源,它就是集成测试,应放在相应层级。
  • 不使用真实的 sleep 或任意超时;改用 fake timers 或等待条件满足。
  • 控制时钟和随机性(fake timers、带种子的 RNG、注入的 now())。
  • 不依赖真实网络、系统日期、区域设置或时区;在测试配置中固定时区。
  • 测试可以按任意顺序运行,也可以并行运行——不得共享可变文件、数据库行或全局状态。
  • 在 afterEach 中清理,并确保测试失败时也会执行清理。
coverage → references/coverage.md
  • 应将覆盖率视为未验证内容的映射,而不是需要达到的分数——只有断言依赖某一行代码时,该行才算覆盖。
  • 测试分支和边界,而不只是能提高行覆盖率的正常路径。
  • 检查关键逻辑(金额、身份验证、权限、迁移)的边界情况;在有价值的地方进行变异测试。
  • 不要只为提高数字而编写测试;移除没有断言、断言恒真的测试、重复测试,以及覆盖已删除代码的测试。

范围

此技能评判单个测试,不涵盖:

  • 测试套件策略和测试金字塔——单元测试、集成测试和端到端测试的占比,契约测试,以及覆盖率在哪些方面最有价值。这属于 architecture-and-design 中的 testing 组。
  • 框架机制——React Testing Library 查询和 user-event、Angular TestBed 和 HttpTestingController、Vue Testing Library 和 @vue/test-utils、组件测试工具。这些内容属于 react、angular 和 vue 中的 testing 组。
  • 端到端测试设计(Playwright、Cypress):选择器、按工作进程划分的数据、重试、分片。这属于 e2e-testing。
  • 性能和负载测试。
  • 无障碍测试——通过角色查询的组件测试也可作为无障碍检查,但完整的视角请参阅 accessibility。
  • 选择和配置测试运行器(Vitest、Jest、node:test),以及 CI 并行化。

此技能说明什么样的测试值得保留。它不能替代运行测试套件并查看实际失败的内容。


参考

此技能与以下内容配合使用:

  • architecture-and-design — 决定测试套件的结构以及每一层要测试的内容。如果发生冲突,它决定策略;此技能决定单个测试。
  • react / angular / vue — 提供渲染、查询和驱动组件的框架机制;此技能关于断言内容的规则在此基础上适用。
  • core-typescript — 测试代码也是代码:使用 strict,测试夹具中不使用 any,使用类型化构建器,收窄错误断言。
  • accessibility — 通过角色和可访问名称查询,既是行为断言,也是无障碍信号;完整的视角请参阅该处。

评论

支持 Markdown