关于 mutation-testing
mutation-testing 是评估和改进测试有效性的实践指南,适合希望确认测试能否发现缺陷的开发者。它介绍变异、测试执行、存活变异分析,并涵盖 Stryker 和 Agent 驱动的流程。
主要功能
- 01通过代码变异检验测试
- 02计算变异分数
- 03定位存活变异
- 04介绍 Stryker 配置与运行
- 05支持 Agent 驱动分析
适用场景
- 01评估测试套件质量
- 02发现断言覆盖缺口
- 03发布前验证关键路径
- 04针对存活变异补充测试
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ proffesor-for-testing/ agentic-qe --skill mutation-testing安装后在 Claude Code 中输入/mutation-testing确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
config.jsonrun-history.jsonevals/mutation-testing.yamlreferences/mutation-operators.mdschemas/output.jsonscripts/validate-config.jsontest-data/sample-output.json详细介绍
变异测试
<default_to_action> 在验证测试质量或提升测试效果时:
- 对代码进行变异(将 + 改为 -,将 >= 改为 >,删除语句)
- 针对每个变异体运行测试
- 验证测试能捕获变异(杀死变异体)
- 找出存活的变异体(测试需要改进)
- 加强测试,杀死存活的变异体
快速变异指标:
- 变异得分 = 已杀死的变异体 /(已杀死的变异体 + 存活的变异体)
- 目标:变异得分 > 80%
- 存活的变异体 = 测试较弱
成功的关键因素:
- 高覆盖率 ≠ 好测试(100% 覆盖率,0% 断言)
- 变异测试可证明测试确实能捕获 Bug
- 优先关注关键代码路径 </default_to_action>
快速参考卡
适用场景
- 评估测试套件质量
- 发现测试断言中的缺口
- 证明测试能捕获 Bug
- 重要版本发布前
变异得分解读
| 得分 | 解读 |
|---|---|
| 90%+ | 测试质量极佳 |
| 80-90% | 良好,只需少量改进 |
| 60-80% | 需要关注 |
| < 60% | 存在明显缺口 |
常见变异操作符
| 类别 | 原始代码 | 变异体 |
|---|---|---|
| 算术 | a + b | a - b |
| 关系 | x >= 18 | x > 18 |
| 逻辑 | a && b | a || b |
| 条件 | if (x) | if (true) |
| 语句 | return x | (已删除) |
变异测试的工作原理
// Original code
function isAdult(age) {
return age >= 18; // ← Mutant: change >= to >
}
// Strong test (catches mutation)
test('18 is adult', () => {
expect(isAdult(18)).toBe(true); // Kills mutant!
});
// Weak test (mutation survives)
test('19 is adult', () => {
expect(isAdult(19)).toBe(true); // Doesn't catch >= vs >
});
// Surviving mutant → Test needs boundary value
使用 Stryker
# Install
npm install --save-dev @stryker-mutator/core @stryker-mutator/jest-runner
# Initialize
npx stryker init
配置:
{
"packageManager": "npm",
"reporters": ["html", "clear-text", "progress"],
"testRunner": "jest",
"coverageAnalysis": "perTest",
"mutate": [
"src/**/*.ts",
"!src/**/*.spec.ts"
],
"thresholds": {
"high": 90,
"low": 70,
"break": 60
}
}
运行:
npx stryker run
输出:
Mutation Score: 87.3%
Killed: 124
Survived: 18
No Coverage: 3
Timeout: 1
修复存活的变异体
// Surviving mutant: >= changed to >
function calculateDiscount(quantity) {
if (quantity >= 10) { // Mutant survives!
return 0.1;
}
return 0;
}
// Original weak test
test('large order gets discount', () => {
expect(calculateDiscount(15)).toBe(0.1); // Doesn't test boundary
});
// Fixed: Add boundary test
test('exactly 10 gets discount', () => {
expect(calculateDiscount(10)).toBe(0.1); // Kills mutant!
});
test('9 does not get discount', () => {
expect(calculateDiscount(9)).toBe(0); // Tests below boundary
});
Agent 驱动的变异测试
// Analyze mutation score and generate fixes
await Task("Mutation Analysis", {
targetFile: 'src/payment.ts',
generateMissingTests: true,
minScore: 80
}, "qe-test-generator");
// Returns:
// {
// mutationScore: 0.65,
// survivedMutations: [
// { line: 45, operator: '>=', mutant: '>', killedBy: null }
// ],
// generatedTests: [
// 'test for boundary at line 45'
// ]
// }
// Coverage + mutation correlation
await Task("Coverage Quality Analysis", {
coverageData: coverageReport,
mutationData: mutationReport,
identifyWeakCoverage: true
}, "qe-coverage-analyzer");
Agent 协作提示
记忆命名空间
aqe/mutation-testing/
├── mutation-results/* - Stryker reports
├── surviving/* - Surviving mutants
├── generated-tests/* - Tests to kill mutants
└── trends/* - Mutation score over time
集群协作
const mutationFleet = await FleetManager.coordinate({
strategy: 'mutation-testing',
agents: [
'qe-test-generator', // Generate tests for survivors
'qe-coverage-analyzer', // Coverage correlation
'qe-quality-analyzer' // Quality assessment
],
topology: 'sequential'
});
相关技能
- tdd-london-chicago - 先编写有效的测试
- test-design-techniques - 边界值分析
- quality-metrics - 衡量测试效果
请记住
高代码覆盖率 ≠ 好测试。 100% 覆盖率但断言薄弱 = 毫无用处。变异测试可证明测试确实能捕获 Bug。
优先关注关键路径。 不要对所有内容都进行变异测试——优先测试支付、身份验证和数据完整性相关代码。
使用 Agent: Agent 会运行变异分析、找出存活的变异体,并生成缺失的测试用例来杀死它们,从而自动提升测试质量。
运行历史
每次运行变异测试后,将结果追加到此技能目录中的 run-history.json:
node -e "
const fs = require('fs');
const h = JSON.parse(fs.readFileSync('.claude/skills/mutation-testing/run-history.json'));
h.runs.push({date: new Date().toISOString().split('T')[0], mutation_score_pct: SCORE, killed: KILLED, survived: SURVIVED});
fs.writeFileSync('.claude/skills/mutation-testing/run-history.json', JSON.stringify(h, null, 2));
"
每次运行前读取 run-history.json,以跟踪得分随时间的变化。
技能组合
- 变异测试前 → 运行
/qe-test-generation,确保已有测试 - 获得变异测试结果后 → 使用
/qe-coverage-analysis,确定改进方向的优先级 - 质量门禁 → 将结果提供给
/qe-quality-assessment,以决定是否发布
注意事项
- 如果同时安装了 jest 和 vitest,Stryker 需要显式指定
--testRunner jest - 将日期比较中的
>=变异为>通常不会被杀死——添加边界测试 - 在超过 500 LOC 的文件上运行会超时;使用
--mutate指定目标函数 --concurrency默认值为 CPU 数量,在容器中可能导致内存溢出——将其设为 2
评论
支持 Markdown