关于 test-guard
Test Guard 是用于检查新增或修改测试代码的 Skill,面向编写测试的编码 Agent 和代码审查者。它着重识别重复、过度模拟和只验证框架行为的测试,并提供按规则组织的审查结果。
主要功能
- 01按九项规则审查测试
- 02检查模拟是否位于系统边界
- 03识别重复及无必要测试
- 04审查测试命名与覆盖对象
- 05按文件汇总违规及修复建议
适用场景
- 01提交前审查新增测试代码
- 02精简重复或维护成本高的测试
- 03审查测试是否验证项目自身逻辑
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ amelnagdy/ guard-skills --skill test-guard安装后在 Claude Code 中输入/test-guard确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlreferences/jest.mdllm-app-testing.mdphpunit.mdpytest.md详细介绍
Test Guard
在生成或修改的测试代码发布前进行审查。在首轮测试编写完成后、测试提交、合并或展示给用户前,执行以下规则。要做敏锐的审查者,而非吹毛求疵的人:指出会增加维护成本或掩盖真实缺陷的问题,忽略纯粹的风格偏好。
制定这些规则,是因为编码 Agent 往往会过度生成测试。常见问题包括:充斥 mock、断言实现细节的单元测试;测试主体几乎重复、仅相差一个值;以及重复验证框架本身而非项目逻辑的测试。这些测试在 diff 中看似工作量充足,却会永久增加维护成本。
此技能的适用时机
- 编码 Agent 刚刚用任何语言编写了新的测试函数或测试文件
- 你正在编辑现有测试
- 你正在审查包含测试变更的 diff
- 用户要求你编写、添加或审查测试
先适应项目
这些规则具有普适性,但具体应用因项目而异。审查前:
- 检查项目自身的 Agent 指引(CLAUDE.md、AGENTS.md)和测试文档。如果项目专属的测试规则与此技能冲突,以项目规则为准。
- 确定测试技术栈,然后阅读对应的参考文档,了解具体模式:
- Python / pytest → references/pytest.md
- PHP / PHPUnit / Pest / WordPress → references/phpunit.md
- JavaScript / TypeScript / Jest / Vitest → references/jest.md
- 如果项目调用 LLM API、使用 Agent 框架,或接入可观测性/遥测,也要阅读 references/llm-app-testing.md——其中补充了三条针对 LLM 应用的规则。
- 梳理项目的系统边界:网络调用、数据库、文件系统、时钟和随机性、第三方 SDK、LLM API。现有的 fixture 和测试辅助工具通常能体现项目已有的边界划分方式。
要做什么
- 阅读测试代码:diff、新文件或正在修改的部分。
- 根据以下规则逐一检查每项测试。
- 简明报告违规项:规则编号、位置、违规原因和建议的修复方式。
- 如果用户在编写测试前明确要求使用此技能,就在编写时应用这些规则——不要先写出违规测试再指出问题。
编写新测试时,针对每项测试都要问:“这项测试能捕获什么其他测试都捕获不了的具体缺陷?”如果无法清楚回答,就不要编写这项测试。
九条规则
规则 1:测试行为,而非实现
从调用者的角度测试代码的行为。断言返回值和可观察到的副作用。绝不要断言某个内部辅助函数是否以特定参数被调用——这样的测试每次重构都会失效,却捕获不了任何问题。
违规模式: 断言内部函数的 mock 被调用,而该函数并非系统边界。 修复方式: 断言调用者能观察到的返回值或状态变化。
规则 2:每个 mock 都必须有充分理由
只在系统边界使用 mock:网络和 HTTP 调用、LLM API、数据库、外部文件的文件系统 I/O、时钟和随机性、第三方 SDK。绝不要 mock 内部类或辅助函数来隔离“单元”——人为创建的隔离边界会掩盖值得捕获的集成缺陷。
mock 系统边界时,断言调用者如何处理响应,而不是断言 mock 收到了哪些特定参数。
规则 3:每项测试只覆盖一种场景,变体使用数据驱动
如果两项或更多测试使用完全相同的设置,只在输入/输出值上有所不同,就合并为一个数据驱动测试(@pytest.mark.parametrize、PHPUnit #[DataProvider]、Jest test.each)。
**适合分开编写测试的情况:**设置不同、断言不同、mock 配置不同,或确实属于不同场景,只是碰巧测试了同一个函数。
规则 4:每个测试都必须证明自身的必要性
问问自己:“这个测试能捕获哪些其他测试都无法捕获的 bug?” 删除那些只检查拼写错误、验证数据类的默认值或测试简单直通逻辑的测试。
常见的无正当理由的测试: 构造函数设置属性、函数拒绝类型系统已经禁止的输入、日志消息的字符串格式,以及常量是否等于其字面值。
规则 5:根据场景为测试命名
模式:test_<scenario>_<expected_outcome>。测试名称应像一条需求,而不是照搬函数签名。
| 不佳 | 良好 |
|---|---|
test_parse_response_missing_field | test_malformed_response_falls_back_to_default |
test_get_language_no_class | test_element_without_class_returns_empty_language |
test_add_tags_single_string | test_single_tag_normalizes_to_list |
规则 6:生产环境回归测试弥足珍贵
复现真实生产环境 bug 的测试始终有正当理由。在名称或注释中注明相关事件(日期、问题 ID 或简短描述),绝不可删除。这些测试不受规则 4 限制——相关事件就是它们存在的理由。
规则 7:不要测试框架保证的行为
不要测试验证库是否执行验证、ORM 是否提交、路由器是否返回 404,或测试框架的夹具是否正常工作。要测试基于框架实现的自有逻辑。
违规模式: 即使删除项目的所有自定义代码、只保留框架默认行为,测试仍会通过。
规则 8:状态对象和值对象是真实对象,绝不模拟
绝不要模拟数据模型、DTO、实体或状态对象。应构造真实实例。模拟状态会掩盖字段名称拼写错误和验证错误——而这正是值得捕获的 bug。如果构造真实对象很麻烦,那是设计方面的反馈,不是模拟的理由;添加一个小型构建器或工厂辅助函数。
规则 9:测试基础设施时使用真实基础设施
当数据库查询、架构行为或持久化逻辑就是测试对象时,应使用真实测试数据库,并通过夹具应用真实迁移。在这种情况下模拟会话毫无意义。如果持久化只是被测行为的副作用,则可以模拟数据库。
报告格式
标记违规时,使用以下格式:
**Rule N violation** in `tests/path/file.ext::<test_name>`
- What: <one sentence describing the violation>
- Fix: <one sentence describing what to do instead>
按文件归类违规。如果某个文件没有违规,不要提及它。
严重程度指南
违规并非同等严重。请自行判断:
- 必须修复: 规则 1、2、8——这些规则会掩盖真实 bug 或导致测试脆弱
- 应该修复: 规则 3、4、5、7——这些问题会造成测试臃肿并增加维护负担
- 弥足珍贵: 规则 6——绝不删除,始终允许
- 值得指出: 规则 9——涉及测试架构;应予以标记,但不要因此阻碍小规模更改
参考资料
- references/pytest.md — Python/pytest 模式:参数化、夹具、模拟边界、真实 Pydantic 实例
- references/phpunit.md — PHP/PHPUnit/Pest 模式,包括 WordPress 和 WooCommerce 测试边界
- references/jest.md — Jest/Vitest 模式:test.each、模块模拟、msw、快照规范
- references/llm-app-testing.md — LLM 应用的另外三条规则:提示词契约、可观测性接线、Agent 流程转换
此技能不做什么
- 它不会运行测试。请使用项目的测试运行器。
- 它不会强制执行代码风格——这是代码检查工具的职责。
- 它不会决定测试什么——只决定如何测试。
- 除非有人要求审计,否则它不会标记你未修改文件中的既有违规。