mcpField
M
mutation-testing

mutation-testing

github.com/proffesor-for-testingテスト・品質520117 回インストール今日更新
リポジトリ

mutation-testing について

mutation-testing は、テストの有効性を評価・改善するための実践ガイドです。テストが不具合を検出できるか確認したい開発者向けに、ミューテーション分析、残存ミュータント、Stryker、エージェント駆動の手順を扱います。

主な機能

  1. 01コード変異によるテスト検証
  2. 02ミューテーションスコアの算出
  3. 03残存ミュータントの特定
  4. 04Stryker の設定と実行
  5. 05エージェント駆動分析への対応

活用シーン

  1. 01テストスイートの品質評価
  2. 02アサーションの不足箇所の発見
  3. 03リリース前の重要経路の確認
  4. 04残存ミュータント向けテストの追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/proffesor-for-testing/agentic-qe --skill mutation-testing

インストール後、Claude Code で/mutation-testingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

config.json
run-history.json
evals/
mutation-testing.yaml
references/
mutation-operators.md
schemas/
output.json
scripts/
validate-config.json
test-data/
sample-output.json

詳細

ミューテーションテスト

<default_to_action> テスト品質を検証したり、テストの有効性を高めたりする場合:

  1. コードをミューテーションします(+ を - に変更する、>= を > に変更する、文を削除する)
  2. 各ミュータントに対してテストを実行します
  3. テストがミューテーションを検出することを確認します(ミュータントをキルする)
  4. 生き残ったミュータントを特定します(テストの改善が必要です)
  5. 生き残ったミュータントをキルできるようにテストを強化します

ミューテーションの指標:

  • ミューテーションスコア = キル数 /(キル数 + 生存数)
  • 目標:ミューテーションスコア > 80%
  • 生き残ったミュータント = テストが弱い

成功に不可欠な要素:

  • カバレッジが高い ≠ テストが優れている(カバレッジ 100%、アサーション 0%)
  • ミューテーションテストにより、テストが実際にバグを検出することを証明できます
  • まず重要なコードパスに集中します </default_to_action>

クイックリファレンスカード

使用するタイミング
  • テストスイートの品質を評価するとき
  • テストのアサーションに抜けがないか確認するとき
  • テストがバグを検出することを証明するとき
  • 重要なリリースの前
ミューテーションスコアの解釈
スコア解釈
90%+テスト品質が非常に優れています
80-90%良好です。軽微な改善が必要です
60-80%対応が必要です
< 60%大きな抜けがあります
一般的なミューテーション演算子
カテゴリ元のコードミュータント
算術a + ba - b
関係x >= 18x > 18
論理a && ba || 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
});

エージェント主導のミューテーションテスト

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

エージェント連携のヒント

メモリの名前空間
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'
});

関連スキル


忘れないでください

コードカバレッジが高い ≠ テストが優れている。 カバレッジが 100% でも、アサーションが弱ければ役に立ちません。ミューテーションテストにより、テストが実際にバグを検出することを証明できます。

まず重要なパスに集中します。 すべてをミューテーションテストする必要はありません。決済、認証、データ整合性のコードを優先します。

エージェントを使う場合: エージェントはミューテーション分析を実行し、生き残ったミュータントを特定して、それらをキルするために不足しているテストケースを生成します。テスト品質を自動的に改善できます。

実行履歴

ミューテーションテストを実行するたびに、このスキルのディレクトリにある 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 に設定してください

コメント