进阶 getfoundry.sh 2026-10-10 09:32:11 · 9 阅读

第8章 变异测试

变异测试(Mutation testing)

变异测试通过修改源代码中的微小部分(即“变异体”)并重新运行测试,来衡量测试套件的强度。当至少有一个测试失败时,该变异体被视为被“杀死”。如果修改后的代码仍然通过选定的测试,则该变异体“存活”。

使用以下命令运行变异测试: $ forge test --mutate

Forge 首先运行选定的测试作为基准。只有当基准测试中至少有一个通过且没有失败时,变异测试才会开始。

选择文件 传入路径以仅变异特定文件: $ forge test --mutate src/Vault.sol src/Token.sol

使用 --mutate-path 参数通过 glob 模式选择文件: $ forge test --mutate --mutate-path 'src//*.sol'

使用 --mutate-contract 参数按名称选择合约: $ forge test --mutate --mutate-contract 'Vault|Token'

--mutate-path 和 --mutate-contract 不能同时使用。--mutate-path 也不能与直接传给 --mutate 的明确路径结合使用。

选择测试 常规的测试过滤器仍用于选择基准测试以及针对每个变异体运行的测试: $ forge test --mutate src/Vault.sol --match-contract VaultTest

这使得你可以将变异运行的范围限定在那些本应检测特定合约变更的测试中。

并行工作进程 Forge 并行运行变异体。默认情况下,它使用逻辑 CPU 核心数。

使用 --mutation-jobs 设置工作进程数量: $ forge test --mutate src/Vault.sol --mutation-jobs 4

传入 0 同样会使用逻辑 CPU 核心数: $ forge test --mutate src/Vault.sol --mutation-jobs 0

并行变异测试为每个变异体使用隔离的临时工作区。为了性能,像 lib、node_modules 和 dependencies 这样的依赖目录会通过符号链接引入这些工作区。

超时 使用 --mutation-timeout 为每个变异体设置一个尽力而为的实时(wall-clock)超时时间(以秒为单位): $ forge test --mutate src/Vault.sol --mutation-timeout 30

超时的变异体会与已杀死、存活、跳过和无效的变异体分开报告。

也可以在 foundry.toml 中配置超时: foundry.toml [mutation] timeout = 30

运算符 变异测试支持以下运算符组:

assembly assignment binary-op delete-expression elim-delegate require unary-op

默认启用所有运算符组。在 foundry.toml 中排除特定运算符: foundry.toml [mutation] exclude_operators = ["assembly", "elim-delegate"]

使用 include_operators 重新启用默认被排除的运算符: foundry.toml [mutation] include_operators = ["assembly"]

报告 报告包含以下计数:

Survived:通过选定测试的变异体 Killed:导致测试失败的变异体 Invalid:无法编译或运行的变异体 Skipped:在同一代码段或表达式中,由于另一个变异体已存活而变得冗余的变异体 Timed out:超过 mutation.timeout 或 --mutation-timeout 的变异体

Skipped 和 Invalid 的计数可能因 --mutation-jobs 的不同而变化,因为较高的并行度可能在确认某个变异体存活之前就启动了更多的变异体。 变异分数(mutation score)为: killed / (killed + survived)

优先关注存活的变异体。每个存活变异体都指向你的测试未能捕捉到的源代码位置和变异。

当前,存活的变异体不会导致 forge test --mutate 失败,且尚未提供阈值标志。要在 CI 中对变异测试进行门禁控制,请使用 --json 运行并根据 JSON 输出强制执行你自己的阈值。 $ forge test --mutate --json

JSON 输出的结构如下: { "summary": { "total": 12, "killed": 8, "survived": 2, "invalid": 1, "skipped": 1, "timed_out": 0, "mutation_score": 80.0, "duration_secs": 12.34 }, "survived_mutants": { "src/Vault.sol": [ { "line": 42, "column": 17, "original": ">", "mutant": ">=" } ] } }

局限性 变异测试不能与 --list、--debug、--flamegraph、--flamechart、--junit、--dump、--showmap 或 --showmap-out 结合使用。 变异测试还拒绝包含 ffi = true、可写文件系统权限(这些权限可以访问符号链接的依赖目录)或内联的每测试网络覆盖的项目。

这篇内容有帮助吗?在 GitHub 上建议修改

评论 (0)