mcpField
M
mutation-testing

mutation-testing

github.com/dmoka测试与质量2187 次安装5 周前更新
代码仓库

关于 mutation-testing

mutation-testing 是用于评估测试能否发现代码缺陷的 Agent 技能,通过注入小型变异并重跑测试来检查。它指导从验证基线、限定模块运行到分析幸存变异和报告结果的完整流程。

主要功能

  1. 01检查测试基线及稳定性
  2. 02选择并配置对应技术栈的工具
  3. 03针对单个模块运行变异测试
  4. 04解释并按风险排列幸存变异
  5. 05编写业务结果测试并验证击杀
  6. 06报告评分局限与待审批事项

适用场景

  1. 01评估单元测试能否发现逻辑错误
  2. 02优先检查金额或权限代码的测试缺口
  3. 03不削弱配置地调查幸存变异

安装

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

$npx skills add https://github.com/dmoka/skills --skill mutation-testing

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

包含的文件

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

references/
gotchas.md
judge.md
tools.md

详细介绍

变异测试

覆盖率告诉你代码是否被执行过。变异测试则告诉你,代码出错时测试能否发现。工具一次植入一个小错误(变异体:>= 变成 >,+ 变成 -,或删除某个条件),重新运行测试套件,并记录结果。测试失败会杀死变异体。测试套件仍然全部通过,就说明错误蒙混过关了——每个存活的变异体,都是测试套件在说谎。

参考文件与本文件位于同一目录。如果你是通过 HTTP 而非磁盘获取本文件,请从 https://raw.githubusercontent.com/dmoka/skills/main/skills/mutation-testing/references/ 获取 tools.md、gotchas.md 和 judge.md。

获取原始文本,而非摘要。 许多 Agent 的获取工具会用摘要模型处理页面。它会改写本文件、删掉编号步骤,还会弄乱你即将复制的配置片段。如果获取到的是散文而非下方原样的 Markdown,请使用 curl -sSL <url> 重新获取,并以此为准。

循环

  1. 基线。 完整运行测试套件两次。若结果为红,报告 BLOCKED — 变异测试工具会拒绝红色基线。两次运行的判定结果不一致,说明测试不稳定,其后所有变异体判定都是噪声。将该测试隔离(跳过,并添加注释说明原因以及需要由人类决定的事项),除非你能确认实际缺陷,且修复就在测试中 — 绝不要凭空编造规范来“修复”测试。如果只有端到端测试/仅 CI 运行的测试,或测试套件在本地运行需要几分钟以上,也要报告 BLOCKED — 变异测试需要快速的本地单元测试套件,而这个缺口本身就是发现的问题。在单体仓库中,应在拥有目标模块的包内操作。绝不要为了得到一个数字而排除失败的测试。
  2. 选择工具,根据技术栈决定(见下表)。将其安装在项目本地,并按照 references/tools.md 进行配置 — 绝不要运行工具的交互式初始化向导;请自行编写配置文件。任何全局安装前都要先征求同意。
  3. 首次运行仅针对一个模块 — 选择用户指定的业务关键文件,或静默错误代价最高的文件(金额计算、权限、数据写入)。如果用户没有指定,就自行选择:README 或包的布局通常会指出业务逻辑所在位置,而静默错误代价最高的逻辑所在文件就是起始目标。说明你选择了哪个文件以及原因。在真实代码库中首次运行整个仓库需要数小时,而且常常会失败;针对一个模块运行只需几分钟,就能证明问题所在。首次运行成功后再扩大范围。如果项目足够小,一个模块就是整个代码库,请说明这一点并继续 — 不要为了满足这一步而刻意缩小范围。
  4. 运行工具时仅输出到控制台,以免在磁盘上留下报告文件(各工具对应的标志见 references/tools.md),并从控制台读取存活的变异体。
  5. 用一句话解释每个存活的变异体,让非测试人员也能理解:变异体改了什么,以及它会允许哪一个具体输入产生错误输出。示例:“2000 分的上限被删除了:一笔 €1,000 的订单会收取 €30 费用,而不是 €20 的上限金额。”保留数字;“大额订单收费过高”没有告诉读者需要检查什么。
  6. 按影响范围排列存活的变异体:优先处理金额和数据丢失路径,其次是边界条件,最后是日志和格式问题。
  7. 消灭变异体或提出主张。 对每个可消灭的存活变异体,编写一个断言业务结果的测试,并重新运行工具确认变异体已被消灭。对于无法消灭的变异体,绝不要自行将其标记为等价 — 想让门禁变绿的 Agent 最有可能把可消灭的变异体称为不可消灭。请改为提出主张:说明为何没有任何输入能区分变异体和原始代码,无论是单独来看还是仅在上下文中如此(references/gotchas.md)。
  8. 在各自全新的 Agent 中审查每项主张,每项主张对应一名审查者。使用 Claude Code 子 Agent(Agent 工具)、其他工具框架的子 Agent 或委托工具,否则就开启新会话;绝不要在自己的上下文中审查。逐字传入 references/judge.md,并且只附上原始代码行及其函数、变异体、主张和测试命令。立即启动所有审查者,并等待所有判定结果。如果审查者找到能消灭变异体的输入:驳回该主张;保留该测试并重新运行工具确认变异体已被消灭。如果在简述规定的范围内未找到:主张成立,标记为“已审查:未找到可区分输入”。
  9. 排除前只征求一次同意。 列出每项仍成立的主张及其审查备注,并一次性询问用户是否批准排除。只有得到肯定答复后,才能为每一行添加工具要求的排除注释并说明原因(语法见 references/tools.md)。未经肯定答复,绝不要写排除注释。如果无人可询问(非交互式运行、CI):不写排除注释,将仍成立的主张报告为待决事项,并让门禁保持红色。
  10. 报告时结果优先,最多 200 个词:
    • 一行:工具名称和分数,后接“N 个已消灭,M 个需要你批准”。
    • 一个表格,每个存活的变异体占一行:变异体(file:line,原始代码 → 变异体)· 变化内容,即第 5 步中的具体输入和错误输出 · 已消灭(新测试的名称)或需要你批准(用几个词概括审查者的判定)。每个单元格用一个简短分句。
    • 第 9 步中的审批问题,用一两句话表达;或者在无人可答时写“待决事项”。
    • 一句话说明分数无法检测到什么(见下文)。再用一句话说明新增或修改的文件,以及磁盘上遗留的任何工具输出。 不包含其他内容:不写设置过程,也不写基线情况,除非运行被 阻塞或不稳定;不列出评审者尝试过的输入。

按技术栈划分的工具

技术栈工具
JavaScript / TypeScriptStrykerJS
C# / .NETStryker.NET
Java / KotlinPitest
Pythonmutmut
Rustcargo-mutants
PHPInfection
Go、Ruby 等参见 references/tools.md

每种工具的设置、配置和限定运行命令:参见 references/tools.md。

严格规则

  • 绝不要为了提高分数而更改配置。 分数只是传递信息的信使。 排除文件、延长超时、禁用变异算子或跳过测试文件来让测试通过,是 唯一绝对禁止的做法。
  • 杀死变异体的测试必须断言业务结果,而不是变异体行为。 如果你 无法用一句话说明测试为用户保障了什么,那你写这个测试只是为了改变 一个数字——删掉它。
  • 关键路径上只要有一个存活的变异体,就比任何分数都重要。 支付 代码中有存活变异体,即使分数达到 95%,结果仍然不合格。不要追求 100%:等价变异体会让这个目标无法实现,而强求达到 100% 会让迭代 无法收敛。
  • 运行之间可以扩大范围,绝不能缩小。 缩小范围以避开难以杀死的 变异体,就是操纵分数。如果工具通过持久配置文件限定范围,完成后 要扩大或移除该限制——遗留的狭窄范围会成为后续人员继承的排除项。
  • 生产源代码只读。 测试、构建文件和工具配置可由你添加和修改—— 报告会列出你改动的每个文件。唯一允许的源代码编辑,是用户在第 9 步 批准的排除注释。如果杀死某个变异体需要修改源代码,应将其作为问题 报告,而不是动手修改。如果某种语言将单元测试放在源文件内(Rust 的 #[cfg(test)] mod tests、Python doctests),你可以在该文件中添加 测试——绝不能触碰测试上方的代码,并在报告中说明你编辑了源文件及其 原因。
  • 每次 Shell 调用只运行一条命令。 不要使用 for 循环、&& 链、 ; 序列或通过管道传给 tail:要求命令白名单授权的测试框架会对 每条复合命令请求许可,而非交互式运行会被拒绝。将基线运行两次,分两次 调用;较长输出请查看工具自带的摘要。
  • 留在仓库内。 临时脚本、下载的本技能副本和等价性检查,都应放在 项目自己的忽略临时目录或你的 Agent 工作区中——不能放在同级目录或 系统临时目录。不要删除或改写仓库外的机器状态来让测试变得确定;如果 测试依赖此类状态,应将其作为问题报告。

分数无法反映的内容

变异测试会根据已编写的代码,评估现有测试。未实现的业务规则不会产生 变异体,因此完全缺失的功能也可能得到 100% 的分数。报告分数时,要明确 说明它未覆盖哪些风险——缺失代码这一盲点及其他局限,见 references/gotchas.md。

分数的可靠性取决于工具的变异算子。 这些工具并不等同:有些会逐个 边界地重写运算符,有些则只会替换整个函数体。较弱的变异算子集合即使 得到 100%,也可能掩盖一个未经测试的差一错误。报告分数时,必须注明 工具名称及其已知盲点,绝不能只报一个百分比——各工具的局限见 references/gotchas.md。

不存在普遍适用的好分数。应根据变更的代码设定门槛:其中的每个变异体都 已被杀死,或经用户批准后排除。

完成标准

  • 在纳入范围的代码中,没有任何存活的变异体能够改变金额、权限或已存储的记录。
  • 每个剩余的存活变异体,都有一条书面声明说明新的裁决者未能将其杀死。每条排除注释都经过裁决并获用户批准;未获任何人批准的声明会作为未决事项报告,不做排除。
  • 每个存活的变异体,都用一句非测试人员也能理解的话加以解释。
  • 你添加的每个测试都断言了一个业务结果,并且已在重新运行时确认能够杀死对应的变异体。
  • 仓库干净:工具输出目录已删除或加入 gitignore,你写入配置的任何范围都已扩大或移除,报告列出了你添加或更改的每个文件。请在文件系统上检查,而不是使用 git status——有些工具会在自己的输出目录中写入 .gitignore,因此 git status 会显示干净,但目录中仍会累积数百 MB 数据。请注明你选择保留的任何输出及其位置。

有未解释的存活变异体,即使分数很高,也不算完成。报告完整,并且用户选择接受了三个已解释、已排序的存活变异体,才算完成。

最后验证时间:2026-10-05,使用 Claude Code(claude-opus-5-5,无头模式,在 TicketBay 上运行 StrykerJS:裁决、审批和报告步骤)。工具设置最后验证时间:2026-09-02(在九个技术栈上进行实时测试)。

评论

支持 Markdown