Test Coverage Guard
トリガー条件
キーワード(いずれか)
- 「テストレビュー」「テストの品質」「偽陽性」「false positive」「テストが信頼できない」
- 「モックが多すぎる」「カバレッジは高いのにバグが出る」「フレイキーテスト」「flaky test」
- 「テスト削除していい?」「このテスト意味ある?」「test review」「mutation testing」
- 「テストスイートが通っているのに不安」「テスト全部通るけど大丈夫?」
状況
- テストGREEN後、スイートの品質に不安がある場面
- PRレビューでテストコードの品質を確認したい場合
非対象(委譲先)
- テスト新規作成 →
test-driven-development - CI/CD設定 →
ci-cd - セキュリティテスト詳細設計 →
security-review
前提条件
- レビュー対象のテストファイルが存在すること
- テストが実行可能な状態(環境構築済み)
- 対象プロジェクトの言語・フレームワークが判明していること
目的
偽陽性: 本来FAILすべきテストがPASSしている状態。緑でも本番で壊れるなら誤った安心感を与えるだけ。
| スキル | 責務 | タイミング | | -------- | ------ | ----------- | | test-driven-development | テスト設計・作成(TDDサイクル) | テストを書く時 | | 本スキル | テスト検証(偽陽性検出・網羅性指摘) | テストGREEN後 |
本スキルはTDDサイクルを中断・上書きしない。不足発見時は「何が不足か」を報告しTDDスキルに委譲。
実行手順
Step 1: スコープ特定
| 戦略 | 適用場面 | | ------ | --------- | | PR差分ベース | PRレビュー・直近変更 | | モジュール単位 | 「この機能のテストをレビューして」 | | リスクベース | カバレッジ低・バグ多・クリティカル機能を優先 | | 全件 | 小規模プロジェクト・初回導入 |
対象範囲が大きい場合は、変更した契約・障害時の影響・実行可能性を根拠に優先順位をつける。
Step 2: 偽陽性スキャン(P1→P2→P3順)
観点別の独立調査
並行調査で独立した検証が増える場合だけ、対象の契約・失敗モードに沿ってsubagentへ分ける。
テスト数やモジュール数は人数を決める根拠にしない。親が十分に読める場合は親が確認する。
使う場合はテストファイル、担当する失敗モード、実際に失敗すべきコード変更、報告形式を明示し、
親が指摘を重複排除して一次ソースを再確認する。dispatchの作法は ${HOME}/.claude/SUBAGENTS.md を参照。
P1(即時修正)
パターン1: アサーション不足
対象の契約を破る到達可能な変更を実行してもテストがPASSするなら、検出すべき失敗を具体的に示す。return null だけを一律に使わず、戻り値・状態変化・副作用から該当するものを確認する。
パターン2: テストダブル過多
Mockの個数だけで判定しない。変更した契約を壊した場合に実際にFAILするかを確認する。外部APIをStubにする場合は実際の型・エラー契約と照合し、DBを含む状態の保証が必要な場合は統合テストで確認する。
パターン3: 呼び出し文脈の欠落
本番フローで前後処理がデータ状態を変える場合、その前処理を再現しているか確認。バッチ・パイプライン・ミドルウェアで起きやすい。
パターン4: privateメソッドの直接テスト
Reflection等でprivate直接テスト → publicメソッド経由の間接検証に置換。 例外(以下すべてを満たす場合のみ):
- 同機能の統合テストが既存でPASS
- 純粋な計算ロジック(副作用なし)
- 統合テストでは網羅困難な境界値
- 抽出不適切の理由をコメント明記
P2(次スプリント)
パターン5: 正常系のみ
以下が不足していないか確認:
- 入力異常: null/空/0/負数/最大値/存在しないID
- 状態異常: 未認証・権限不足・論理削除済み・ロック中
- 外部依存異常: タイムアウト・接続エラー・レート制限
- 境界値: 境界-1 / 境界 / 境界+1 の3点セット
指摘のみ。テスト追加はTDDスキルに委譲。
P3(バックログ)
パターン6: テストデータと本番データの乖離
DB側デフォルト値・バリデーション・関連テーブル連動を再現しているか確認。重要データは本番と同じAPI/サービス経由で作成する。
パターン7: フレイキーの温床
| 原因 | 対策 |
| ------ | ------ |
| テスト間状態共有 | テストごとにDB/状態リセット |
| 非同期待機不足 | waitFor/eventually使用。sleep(固定値) 禁止 |
| 外部サービス依存 | テストダブルまたはテストコンテナ |
| システム時刻依存 | FakeClockで時刻注入 |
| 並列実行リソース競合 | スキーマ分離またはトランザクション分離 |
⚠️ フレイキーテストは原因を調査し、検出している独自の契約を確認したうえで修正する。削除する場合は同じ契約を守る代替テストを先に用意する。
パターン8: スナップショット形骸化
内容確認なしで --update-snapshot している場合は要注意。長さだけで判定せず、重要な契約が更新に埋もれないよう個別のアサーションと差分レビューを確認する。
Step 3: 契約を壊す変更への感度
対象の契約に応じて、戻り値・条件式・重要な副作用などを誤らせる変更を考える。 思考実験は未実行の仮説として記録し、実際にテストがFAILする証拠として扱わない。 安全に試せる場合は隔離環境で最小限の変異を実行し、元のコードへ戻す。 変異後にテストがPASSする場合は、契約が未検証か等価変異かを区別する。
自動mutationを使う場合も、対象範囲・実行した変異・等価変異を記録する。 全プロジェクトへ同じスコアを一律の合否基準として適用しない。
Step 4: テストダブル検証
チェックポイント
- テストダブルを通しても、変更した契約を破るとテストがFAILするか
- レスポンス一致: 型・フィールド名・ネスト構造が実際と一致しているか
- エラーケース: タイムアウト・エラーレスポンス・不正データのStubが存在するか
- 自プロジェクトのDB/クラスをテストダブルで差し替えていないか(実物が原則)
| 種類 | 推奨用途 | | ------ | --------- | | Stub | 外部APIの正常/異常レスポンス | | Mock | 通知送信など副作用の発生確認 | | Fake | InMemoryRepository, FakeClock | | Spy | 実処理維持しつつ呼び出し記録 |
| 対象 | 推奨 | | ------ | ------ | | 外部API(決済・SMS等) | Stub/Mock | | 非決定的な値(時刻・乱数) | Fake | | 自プロジェクトのDB | 状態の整合性が要件なら実物の統合テスト。副作用のない単体テストで無条件に実DBを要求しない | | 自プロジェクトの他クラス | 実物(副作用の呼び出し検証が必要な場合のみ Spy 可) |
Step 5: 網羅性の指摘
- 正常系に対応する異常系テストが存在するか
- エラーレスポンスの型・メッセージ・ステータスと副作用の不在を検証しているか
- セキュリティ関連(未認証拒否・他ユーザーリソースへのアクセス拒否)のテストが存在するか
- 並行性関連(楽観ロック・在庫同時減算・冪等性)のテストが存在するか
不足テストの一覧をレポートに含める。実装はTDDスキルに委譲。
Property-Based Testing(JS/TS: fast-check、Python: Hypothesis)は既存テストの補完として有効。置き換えではない。
Step 6: レポート出力
## テストレビュー結果
### 🔴 要修正(偽陽性リスク: 高)
- **[テスト名]** — パターンN: [具体的な問題] → [修正方針]
### 🟡 改善推奨
- **[テスト名]** — パターンN: [具体的な問題] → [修正方針]
### 🟢 問題なし
- [テスト名]: [検証済みの観点]
### 📊 サマリー
- 検証テスト数: N / 要修正: N件 / 改善推奨: N件 / 問題なし: N件
- 不足テスト候補: [異常系・境界値テストの一覧 → TDDスキルに委譲]
アンチパターン
| 禁止事項 | 理由 |
| --------- | ------ |
| 不足テストを本スキル内で実装する | テスト作成はTDDスキルの責務 |
| TDDサイクルを中断・上書きする | 本スキルは検証専用 |
| sleep(固定値) による非同期待機 | フレイキーの原因 |
| フレイキーテストの放置 | CI全体の信頼性を下げる |
| カバレッジ数値を目標として追う | 価値の低いテストを量産する |
| 既存コードへカバレッジゲートを遡及適用 | 価値の低いテスト量産のインセンティブが生まれる |
テスト削除の判断基準
テストの削除は、何を検出していたかを確認し、同じ契約を別のテストが実際に検証する場合に限る。 保守回数やMock数だけで削除しない。
| 対象 | 判断 | | -------- | ------ | | アサーションなし・トートロジー | 検出力を持たせるか、同じ契約の代替を用意して削除 | | 内部実装のみを写すテスト | 外部契約に沿ったテストへ置き換える | | 不安定なテスト | 原因を直し、代替なしの削除で回帰検出を失わない |
カバレッジの正しい使い方
- 目標ではなくテスト漏れの発見ツールとして使う
- ラインカバレッジよりブランチカバレッジを重視する
- ミューテーションスコアを併用してテストの検出力を直接計測する
- CIゲートは「新規コード/変更コード」に限定する
- 未カバー行をテスト追加の候補リストとして活用する
関連スキルとの連携
| スキル | 連携ポイント | | -------- | ------------ | | test-driven-development | 不足発見時はTDDスキルに戻ってテストケースを追加。本スキルは指摘まで | | ci-cd | テストの段階実行、CIゲート設定 | | security-review | セキュリティテストの詳細設計 | | measure | テスト実行時間のボトルネック調査 |