mcpField
M
mutation-testing

mutation-testing

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

关于 mutation-testing

面向使用变异测试验证测试能否发现缺陷的开发者,提供 TypeScript/JavaScript 的 Stryker 和 Python 的 mutmut 指导,以及结果解读和强化薄弱测试的方法。

主要功能

  1. 01变异测试概念与评分
  2. 02TypeScript 和 JavaScript 的 Stryker 配置
  3. 03Bun 原生运行器指南
  4. 04Python mutmut 命令
  5. 05改进薄弱测试的模式

适用场景

  1. 01检查测试能否捕获代码变更
  2. 02查找测试套件中的薄弱断言
  3. 03增量运行变异测试
  4. 04改善边界条件覆盖

安装

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

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

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

详细介绍

变异测试

变异测试的专业知识——通过引入刻意的代码变异,验证测试是否确实能捕获 Bug。

核心概念

  • 变异体:自动引入的小幅代码改动
  • 被杀死:引入变异后测试失败(好——测试捕获了 Bug)
  • 存活:引入变异后测试通过(不好——测试较弱)
  • 得分:被杀死的变异体所占百分比(目标为 80% 以上)

TypeScript/JavaScript(Stryker)

Vitest 运行器
安装
# Using Bun
bun add -d @stryker-mutator/core @stryker-mutator/vitest-runner

# Using npm
npm install -D @stryker-mutator/core @stryker-mutator/vitest-runner
配置
// stryker.config.mjs
export default {
  packageManager: 'bun',
  reporters: ['html', 'clear-text', 'progress'],
  testRunner: 'vitest',
  coverageAnalysis: 'perTest',
  mutate: ['src/**/*.ts', '!src/**/*.test.ts'],
  thresholds: { high: 80, low: 60, break: 60 },
  incremental: true,
}
Bun 原生运行器(bun test)

适用于直接使用 bun test 的项目(而非 Vitest)。

要求
  • Bun >= 1.3.7(需要 Bun PR #25986 提供的 TestReporter WebSocket 事件)
  • @stryker-mutator/core ^9.6.1
安装
bun add -D @hughescr/stryker-bun-runner @stryker-mutator/core
配置
// stryker.conf.mjs
export default {
  testRunner: 'bun',
  coverageAnalysis: 'perTest',
  mutate: ['src/**/*.ts', '!src/**/*.test.ts'],
  thresholds: { high: 80, low: 60, break: 60 },
  incremental: true,
  bun: {
    inspectorTimeout: 5000,  // WebSocket Inspector connection timeout (ms)
    // bunPath: '/path/to/bun',  // only if custom Bun install
    // timeout: 30000,           // test timeout (ms)
    // env: { DEBUG: 'true' },
    // bunArgs: ['--bail'],
  },
}
关键行为
  • 顺序执行:使用 --concurrency=1 运行测试,以准确获取每个测试的覆盖情况。速度比并行执行慢,但这是正确关联测试与变异体的必要条件。
  • 并发测试修补:在变异测试期间,自动将 describe.concurrent()、test.concurrent()、it.concurrent() 修补为顺序运行——无需修改代码。
  • Inspector 协议:使用 Bun 的 WebSocket Inspector API 发现测试并关联覆盖情况。
运行 Stryker
# Run mutation testing
bunx stryker run

# Incremental mode (only changed files)
bunx stryker run --incremental

# Specific files
bunx stryker run --mutate "src/utils/**/*.ts"

# Open HTML report
open reports/mutation/html/index.html
示例:较弱的测试
// Source code
function calculateDiscount(price: number, percentage: number): number {
  return price - (price * percentage / 100)
}

// ❌ WEAK: Test passes even if we mutate calculation
test('applies discount', () => {
  expect(calculateDiscount(100, 10)).toBeDefined() // Too weak!
})

// ✅ STRONG: Test catches mutation
test('applies discount correctly', () => {
  expect(calculateDiscount(100, 10)).toBe(90)
  expect(calculateDiscount(100, 20)).toBe(80)
  expect(calculateDiscount(50, 10)).toBe(45)
})

Python(mutmut)

安装
uv add --dev mutmut
运行 mutmut
# Run mutation testing
uv run mutmut run

# Show results
uv run mutmut results

# Show specific mutant
uv run mutmut show 1

# Generate HTML report
uv run mutmut html
open html/index.html

常见变异类型

// Arithmetic Operator
// Original: a + b → a - b, a * b, a / b

// Relational Operator
// Original: a > b → a >= b, a < b, a <= b

// Logical Operator
// Original: a && b → a || b

// Boolean Literal
// Original: true → false

变异得分目标

得分质量行动
90%+优秀保持质量
80-89%良好小幅改进
70-79%可接受针对薄弱环节进行改进
< 60%较差需要大幅改进

改进较弱的测试

模式:断言不足
// Before: Mutation survives
test('calculates sum', () => {
  expect(sum([1, 2, 3])).toBeGreaterThan(0) // Weak!
})

// After: Mutation killed
test('calculates sum correctly', () => {
  expect(sum([1, 2, 3])).toBe(6)
  expect(sum([0, 0, 0])).toBe(0)
  expect(sum([])).toBe(0)
})
模式:边界条件
// After: Tests boundaries
test('validates age boundaries', () => {
  expect(isValidAge(18)).toBe(true)   // Min valid
  expect(isValidAge(17)).toBe(false)  // Just below
  expect(isValidAge(100)).toBe(true)  // Max valid
  expect(isValidAge(101)).toBe(false) // Just above
})

最佳实践

  • 从核心业务逻辑模块开始
  • 在进行变异测试前,确保覆盖率达到 80% 以上
  • 增量运行(仅针对已更改的文件)
  • 优先关注重要文件
  • 不要期望变异得分达到 100%(存在等价变异体)

工作流

# 1. Ensure good coverage first
bun test --coverage
# Target: 80%+ coverage

# 2. Run mutation testing
bunx stryker run

# 3. Check report
open reports/mutation/html/index.html

# 4. Fix survived mutants
# 5. Re-run incrementally
bunx stryker run --incremental
# or: npx stryker run --incremental

另请参阅

  • vitest-testing - 单元测试框架
  • test-quality-analysis - 检测测试异味

评论

支持 Markdown