mutation-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMutation Testing
Mutation Testing
Expert knowledge for mutation testing - validating that your tests actually catch bugs by introducing deliberate code mutations.
关于Mutation Testing的专业知识——通过引入刻意的代码突变来验证你的测试是否真的能发现bug。
Core Concept
核心概念
- Mutants: Small code changes introduced automatically
- Killed: Test fails with mutation (good - test caught the bug)
- Survived: Test passes with mutation (bad - weak test)
- Score: Percentage of mutants killed (aim for 80%+)
- Mutants:自动引入的微小代码变更
- Killed:测试在突变后失败(良好——测试发现了bug)
- Survived:测试在突变后仍通过(不佳——测试薄弱)
- Score:被杀死的突变体占比(目标80%以上)
TypeScript/JavaScript (Stryker)
TypeScript/JavaScript(Stryker)
Installation
安装
bash
undefinedbash
undefinedUsing Bun
Using Bun
bun add -d @stryker-mutator/core @stryker-mutator/vitest-runner
bun add -d @stryker-mutator/core @stryker-mutator/vitest-runner
Using npm
Using npm
npm install -D @stryker-mutator/core @stryker-mutator/vitest-runner
undefinednpm install -D @stryker-mutator/core @stryker-mutator/vitest-runner
undefinedConfiguration
配置
typescript
// 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,
}typescript
// 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,
}Running Stryker
运行Stryker
bash
undefinedbash
undefinedRun mutation testing
Run mutation testing
bunx stryker run
bunx stryker run
Incremental mode (only changed files)
Incremental mode (only changed files)
bunx stryker run --incremental
bunx stryker run --incremental
Specific files
Specific files
bunx stryker run --mutate "src/utils/**/*.ts"
bunx stryker run --mutate "src/utils/**/*.ts"
Open HTML report
Open HTML report
open reports/mutation/html/index.html
undefinedopen reports/mutation/html/index.html
undefinedExample: Weak Test
示例:薄弱测试
typescript
// 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)
})typescript
// 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)
Python(mutmut)
Installation
安装
bash
uv add --dev mutmutbash
uv add --dev mutmutRunning mutmut
运行mutmut
bash
undefinedbash
undefinedRun mutation testing
Run mutation testing
uv run mutmut run
uv run mutmut run
Show results
Show results
uv run mutmut results
uv run mutmut results
Show specific mutant
Show specific mutant
uv run mutmut show 1
uv run mutmut show 1
Generate HTML report
Generate HTML report
uv run mutmut html
open html/index.html
undefineduv run mutmut html
open html/index.html
undefinedCommon Mutation Types
常见突变类型
typescript
// 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 → falsetypescript
// 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 → falseMutation Score Targets
突变分数目标
| Score | Quality | Action |
|---|---|---|
| 90%+ | Excellent | Maintain quality |
| 80-89% | Good | Small improvements |
| 70-79% | Acceptable | Focus on weak areas |
| < 60% | Poor | Major improvements needed |
| 分数 | 质量等级 | 行动建议 |
|---|---|---|
| 90%+ | 优秀 | 维持现有质量 |
| 80-89% | 良好 | 小幅优化 |
| 70-79% | 合格 | 聚焦薄弱领域 |
| < 60% | 较差 | 需要大幅改进 |
Improving Weak Tests
优化薄弱测试
Pattern: Insufficient Assertions
模式:断言不足
typescript
// 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)
})typescript
// 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)
})Pattern: Boundary Conditions
模式:边界条件
typescript
// 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
})typescript
// 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
})Best Practices
最佳实践
- Start with core business logic modules
- Ensure 80%+ coverage before mutation testing
- Run incrementally (only changed files)
- Focus on important files first
- Don't expect 100% mutation score (equivalent mutants exist)
- 从核心业务逻辑模块开始
- 在进行突变测试前确保测试覆盖率达到80%以上
- 以增量模式运行(仅针对变更的文件)
- 优先关注重要文件
- 不要追求100%的突变分数(存在等效突变体)
Workflow
工作流程
bash
undefinedbash
undefined1. Ensure good coverage first
1. Ensure good coverage first
bun test --coverage
bun test --coverage
Target: 80%+ coverage
Target: 80%+ coverage
2. Run mutation testing
2. Run mutation testing
bunx stryker run
bunx stryker run
3. Check report
3. Check report
open reports/mutation/html/index.html
open reports/mutation/html/index.html
4. Fix survived mutants
4. Fix survived mutants
5. Re-run incrementally
5. Re-run incrementally
bunx stryker run --incremental
bunx stryker run --incremental
or: npx stryker run --incremental
or: npx stryker run --incremental
undefinedundefinedSee Also
相关参考
- - Unit testing framework
vitest-testing - - Detecting test smells
test-quality-analysis
- - 单元测试框架
vitest-testing - - 检测测试异味
test-quality-analysis