agentsclimarketplace

Mutation testing

Skill secondsky/claude-skills/plugins/mutation-testing/skills/mutation-testing

Production-ready skills for Claude Code CLI - Cloudflare, React, Tailwind v4, and AI integrations

Install
npx -y skills add secondsky/claude-skills --skill mutation-testing

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Validate test effectiveness with mutation testing using Stryker (TypeScript/JavaScript with Vitest or bun test via @hughescr/stryker-bun-runner) and mutmut (Python). Find weak tests that pass despite code mutations. Use to improve test quality.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

5.5 KB, as published. Nobody here has run it

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)

Vitest Runner

Installation

# Using Bun
bun add -d @stryker-mutator/core @stryker-mutator/vitest-runner

# Using npm
npm install -D @stryker-mutator/core @stryker-mutator/vitest-runner

Configuration

// 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 Native Runner (bun test)

Use when projects use bun test directly (not Vitest).

Requirements

  • Bun >= 1.3.7 (needs TestReporter WebSocket events from Bun PR #25986)
  • @stryker-mutator/core ^9.0.0

Installation

bun add -D @hughescr/stryker-bun-runner @stryker-mutator/core

Configuration

// 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'],
  },
}

Key Behaviors

  • Sequential execution: Runs tests with --concurrency=1 for accurate per-test coverage. Slower than parallel but required for correct test-to-mutant correlation.
  • Concurrent test patching: Automatically patches describe.concurrent(), test.concurrent(), it.concurrent() to run sequentially during mutation testing — no code changes needed.
  • Inspector Protocol: Uses Bun's WebSocket Inspector API to discover tests and correlate coverage.

Running 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

Example: Weak Test

// 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)

Installation

uv add --dev mutmut

Running 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

Common Mutation Types

// 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

Mutation Score Targets

ScoreQualityAction
90%+ExcellentMaintain quality
80-89%GoodSmall improvements
70-79%AcceptableFocus on weak areas
< 60%PoorMajor improvements needed

Improving Weak Tests

Pattern: Insufficient Assertions

// 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

// 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)

Workflow

# 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

See Also

  • vitest-testing - Unit testing framework
  • test-quality-analysis - Detecting test smells

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.