| name | mutation-testing |
| description | Validate test effectiveness with mutation testing using Stryker (TypeScript/JavaScript) and mutmut (Python). Find weak tests that pass despite code mutations. Use to improve test quality. |
| allowed-tools | Bash, Read, Edit, Write, Grep, Glob, TodoWrite |
Mutation Testing
Expert knowledge for mutation testing - validating that your tests actually catch bugs by introducing deliberate code mutations.
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%+)
TypeScript/JavaScript (Stryker)
Installation
bun add -d @stryker-mutator/core @stryker-mutator/vitest-runner
npm install -D @stryker-mutator/core @stryker-mutator/vitest-runner
Configuration
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
bunx stryker run
bunx stryker run --incremental
bunx stryker run --mutate "src/utils/**/*.ts"
open reports/mutation/html/index.html
Example: Weak Test
function calculateDiscount(price: number, percentage: number): number {
return price - (price * percentage / 100)
}
test('applies discount', () => {
expect(calculateDiscount(100, 10)).toBeDefined()
})
test('applies discount correctly', () => {
expect(calculateDiscount(100, 10)).toBe(90)
expect(calculateDiscount(100, 20)).toBe(80)
expect(calculateDiscount(50, 10)).toBe(45)
})
Python (mutmut)
Installation
uv add --dev mutmut
Running mutmut
uv run mutmut run
uv run mutmut results
uv run mutmut show 1
uv run mutmut html
open html/index.html
Common Mutation Types
Mutation 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 |
Improving Weak Tests
Pattern: Insufficient Assertions
test('calculates sum', () => {
expect(sum([1, 2, 3])).toBeGreaterThan(0)
})
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
test('validates age boundaries', () => {
expect(isValidAge(18)).toBe(true)
expect(isValidAge(17)).toBe(false)
expect(isValidAge(100)).toBe(true)
expect(isValidAge(101)).toBe(false)
})
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)
Workflow
bun test --coverage
bunx stryker run
open reports/mutation/html/index.html
bunx stryker run --incremental
See Also
vitest-testing - Unit testing framework
test-quality-analysis - Detecting test smells