关于 test-audit
test-audit 是面向测试套件维护者的仓库专用 Skill,规定新增测试、审计和精简测试的流程。它要求在修改前提供证据,并按行为价值判断测试的保留与否。
主要功能
- 01新增、审计和套件清理三种模式
- 02以行为为中心的测试保留标准
- 03候选删除项的证据清单
- 04边界测试与验证流程
适用场景
- 01评估新增测试是否必要
- 02查找重复或耦合实现的测试
- 03规划全套件测试清理
- 04记录测试变更的证据与验证
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ every-app/ open-seo --skill test-audit安装后在 Claude Code 中输入/test-audit确认已加载。
详细介绍
测试审计
三种模式,同一价值标准。编写模式在每个新增或变更的测试写入时进行把关。审计模式针对以下测试开展有重点的检查:重复验证源代码、重复更强的证明、将行为与实现耦合,或让仅供测试使用的生产代码接缝持续存在。专项模式在维护者要求精简整个测试套件时,逐个审查所有测试文件并给出每项测试的判定;请参阅专项模式。优化目标是提升信心,而非增加删除数量。每个 PR 合并一个连贯的批次;范围较广的审计则作为单独的后续工作继续进行。
仓库自身的规则位于 AGENTS.md 的“Testing”部分。本技能用于说明如何应用这些规则;若两者有冲突,以 AGENTS.md 为准,并更新本文件。
编写把关
添加测试前,先回答以下四个问题。任何一项没有答案,都意味着暂时不要添加:
- 它保护的是哪种可观察行为、不变量或独立契约?
- 哪种可信的回归会导致它失败?
- 为什么现有覆盖无法捕获该问题?每项契约都应在最强边界(通常是服务或 MCP 工具处理程序,而非仓库或私有辅助函数)由一个主要测试负责。其他层需要有自身独特的风险。与其编写近似重复的测试,不如优先扩展表驱动用例或共享工厂(
ga4-test-fixtures.ts、tool-test-support.ts),并在同一变更中合并重复的设置代码。 - 它是否需要生产代码中没有调用方的接缝(导出、标志、包装器、注入钩子)?如果需要,应改为在真正的边界进行测试。用 grep 搜索整个仓库的调用方,而不只是
src/;scripts/也算。
然后,根据每种无用测试模式检查该测试;若符合其中任一模式,则未通过把关,除非保留标准明确指出它独立保护的契约。如果某项测试会因不改变行为的重构而失败,那它断言的是实现,而非行为;应在所属边界重写后再合并。
针对 Bug 的回归测试必须在修复前的代码上因预期原因失败,并在修复后通过。若回归测试从未被明确证明会失败,它证明的是 mock,而不是修复。针对该 Bug 的回归测试在负责该 Bug 的边界编写一项即可;不要在它经过的每一层重复编写。
不良模式
这份清单适用于两种模式。新增测试若符合其中一项,作者门禁会拒绝;审计则会查找已有的此类测试。
仓库特定(每项都是一条 AGENTS.md 规则):
- 在每个测试中使用
await import()或vi.resetModules(),却没有注释说明必须重置哪些模块级状态; - 在测试中重新声明生产类,而不是从叶子模块导入(模式示例:
ga4Errors.ts、gscErrors.ts); - 在
beforeEach中进行mockReset/mockClear操作(Vitest 的clearMocks已启用); - 固定数据比读取它们的断言还长,或内联复制已有工厂函数的结构;
- 通过被测模块重新测试 Zod 模式或第三方库;
- 在每个正常路径中重复进行输出模式往返测试;
- 模拟 Drizzle 构建器链(使用
vi.fn()链模拟select().from().where());应通过服务测试仓库,或使用真实 SQL; - 在参数映射并非契约时断言传递给模拟对象的参数(计费参数和遥测事件才是契约;内部辅助函数的参数不是)。
通用:
- 不含断言的覆盖率探测;
- 自我比较,以及由被测辅助函数或渲染器生成的预期值;
- 复制的固定数据、清单、清单文件或导出列表;
- 对源码、导入或字符串进行精确 grep;
- 在真实边界处重复测试私有谓词或调用形式;
- 对同一契约重复调用;
- 唯一目的在于保留仅供测试使用的导出项或包装器的测试;
- 唯一调用方是测试的无用生产代码;
- 实现了被断言行为的模拟对象,或用同一个模拟对象代表不同 API;
- 因无关原因而通过的负向对照,例如被另一个守卫拒绝,或生产路径根本不会触发的拒绝;
- 名称或固定数据所表达的内容超出输入实际覆盖的范围。
价值门槛
测试通过保护行为、可信的回归风险或独立且有意义的契约,证明其维护成本物有所值。在审计中,若行为不变的源码重组仍要求修改某个现有测试,则该测试值得怀疑,但并不意味着应自动删除;作者门禁仍会拒绝新增此类测试。
评估候选项前,请完整阅读测试及其生产代码归属方、入口点、调用方、被调用方、同级实现、重叠测试和相关 Git 历史记录。如果测试声称行为由依赖项支持(DataForSEO 响应结构、Autumn、Better Auth、Drizzle),请直接检查依赖项源码或类型定义。
发现
发现阶段应保持只读,并在编辑前报告证据。对于较大范围的检查,请并行开展只读任务(Explore 子代理很适用):
src/server/mcp/和src/server/mcp/tools/;src/server/lib/、src/server/auth/、src/server/billing/、src/server/workflows/、src/serverFunctions/;src/server/features/;src/client/、src/shared/、src/lib/、src/types/、scripts/、web/tests/,以及针对上述仓库特定模式的跨领域 grep 扫描。
与其列出大量推测性候选项,不如优先选择少数把握较高的候选项。
Campaign 模式
仅在维护者明确要求全套精简时使用。将流程分为两个阶段,并为每个阶段分配互不重叠的文件切片,确保 Agent 不会编辑同一文件:
- 审查,只读。 将所有
*.test.ts按行数均衡地拆分为 6-8 个切片,并按目录分组。每个切片安排一名审查者,完整阅读每个测试文件及其生产代码归属文件,并编写报告;每个文件对应一张表格,列出:测试名称、DELETE / MERGE / KEEP、用一行证据说明哪项代码变更会导致测试失败,或哪个测试已覆盖该行为。报告还应列出仅供测试使用的生产代码接口(并检查src/、scripts/、tests/badseo/、web/中的调用方)、因此会变得未使用的测试支持代码、要删除的整个文件,以及“高风险调用”一节。审查者不得编辑文件。 - 应用变更,按切片进行。 每个切片安排一名执行者,在操作前根据源代码重新核实每项 DELETE 和 MERGE;证据不成立的内容一律保留,将 MERGE 行合并到表驱动的同类测试中,删除新近未使用的固定数据和 mock,并跳过所有高风险项,将其列出并交还维护者。如果某项删除的理由引用了另一个切片中的测试,执行者需在本次运行结束时确认该测试仍然存在。
整个精简过程中均适用以下规则:
- 唯一允许的非测试编辑,是从某个辅助函数中移除
export关键字,前提是它剩余的所有调用方均为测试。否则,Knip 会因孤立的导出项导致ci:check失败。即使某个测试看起来是代码存在的唯一理由,也不得在同一变更中移除参数、删除分支或改变行为;应将这些事项报告为后续工作。 src/routes/下的路由模块和 barrel 文件须保留其导出项。- 使用
pnpm exec prettier --write <files>;pnpm format:write会忽略参数并格式化整个仓库。 - 所有切片合并后,按正常顺序运行完整测试套件,并使用
--sequence.shuffle.tests --sequence.seed=<n>运行两到三次。移除重置流程可能会暴露潜在的顺序依赖;应通过在beforeEach中设置 mock 默认值来修复,绝不能恢复重置流程。
保留标准
如果测试独立约束了公共 API、MCP 工具契约、Zod 边界架构、配置、迁移、存储(SQLite 和 Postgres)、计费、身份验证、安全性、默认值、提示词字节内容或包契约,就应保留。此外还应保留:
- 当调用顺序属于可观察行为时,保留验证调用顺序的测试;
- 有可信失败模式的回归测试;
- 当源码检查是成本最低的独立防护措施时,保留源码检查:契约变更时测试会失败,而仅标识符重构时测试仍会通过(契约包括面向用户的键、字节或路径)。
samSkills.test.ts中固定的 SAM 技能清单以及src/db/schema-parity.test.ts中唯一索引一致性检查都属于此类; - 基线版本上会失败的测试:应将其视为可能的产品缺陷,复现问题并修复其归属代码,而不是删除测试。
静态测试或耗时较长都不是删除理由。即使测试看起来与实现重复,也可能仍是独立契约;删除前必须证明并非如此。
候选项证据
编辑前记录每个字段。缺少任何字段,候选项就尚未达到删除条件:
- 测试的确切名称和位置;
- 测试实际能检测到的失败;
- 被覆盖的生产代码或测试支持接口的非测试调用方,包括
scripts/、tests/badseo/和web/(性能分析脚本也算调用方); - 更强的剩余归属边界证明,或说明为何不需要此类证明;
- 相关历史记录,以及该测试或接口存在的原因;
- 删除生产代码或测试支持代码所解锁的内容;
- 风险及针对性的验证命令。
编辑范围
选择一个边界清晰的所有者批次。删除过时的仅供测试使用的导出、包装器和无效的生产代码路径,不要保留别名(Knip 会在 pnpm ci:check 中标记残留项)。将保留的回归测试移至其规范所有者处。将重复断言合并为一个数据驱动的用例。
尽量减少生产代码的净行数。不要添加重复验证相同实现的替代测试,也不要为了增加删除数量而将不确定的候选项纳入清理。
验证
Vitest 正在当前检出目录中运行时,绝不编辑测试。
- 运行所有者及同级测试:
pnpm exec vitest run <path-or-filter>。 - 对于已移除的源码 grep 或静态断言,运行负责真实契约的可执行程序(例如,运行
pnpm sync-plugin-skills检查插件技能漂移)。 - 运行
pnpm format:write,然后运行pnpm ci:check(prettier、knip、tsc、oxlint、插件技能同步)。如果 Knip 因某个导出现在未使用而失败,应删除该导出,而不是重新添加测试。 - 完整测试套件只运行一次:
pnpm test。 - 检查
git diff --numstat;分别报告生产代码/工具代码与测试及测试支持代码的行数。
合并
仅在获得授权时提交、推送或发起 PR。使用 merge-ready 技能完成评审和 PR 流程。如果已验证的发现揭示了 .greptile/ 尚未记录的反复出现的不变量,请使用 maintain-greptile-rules;不要将一次性清理提升为永久规则。沿途遇到的仓库阻碍,请用 papercuts 记录。
交接
报告:
- 删除的低价值类别及其根本原因;
- 生产代码所有者方面的简化;
- 保留的误报及其仍有价值的原因;
- 实际运行过的针对性和完整验证,以及真实输出;
- 生产代码与测试代码的行数;
- PR 和合并状态;
- 明确列出的后续事项。