test-gap-analysis について
テストが呼び出し元から見える本番動作を保護しているか評価する、開発者向けのスキルです。公開される結果とアサーションを対応付け、信頼できるギャップを特定し、絞り込んだ検証やテスト追加を支援します。
主な機能
- 01呼び出し元から見える結果の整理
- 02アサーションと動作の対応付け
- 03境界条件とエラー経路の分析
- 04妥当な変異の生存確認
- 05対象を絞ったテスト追加の案内
活用シーン
- 01コンポーネントのテストカバレッジ確認
- 02指定リスクのテスト有無の確認
- 03テスト追加前のギャップ検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dotnet/ skills --skill test-gap-analysisインストール後、Claude Code で/test-gap-analysisを入力して読み込まれたか確認します。
同梱ファイルreferences/mutation-catalog.mdreferences/per-test-read-only.md
詳細
テストギャップ分析
次の質問に答えてください。**既存のテストが失敗しないまま変わり得る、呼び出し元から見える本番動作は何ですか?**ミューテーション分析は調査手段であり、目的ではありません。まず公開される結果を洗い出し、信頼できるギャップのみを確認してください。
合成時のディスパッチ
判断フローに入る前に、呼び出し元のモードを確認してください。明示的な per-test-read-only リクエスト(grade-tests からの合成を含む)では、references/per-test-read-only.md のみを使用してください。このモードは、ホストがサポートする呼び出し元向け指示で伝えられる評価コンテキストであり、新しいスキルローダーパラメーターやモード固有のスキル名ではありません。そのリファレンスを読み、テストごとの評価をインラインで返してください。以下の単独ワークフローには進まないでください。このモードを読み込んでも、ベースラインの実行、ミューテーションの実行、ファイル編集、テストスイートの検出、委任は許可されません。同梱のリファレンスを利用できない場合は、既知の references/ ディレクトリを一覧表示するのは最大1回までとし、その後、理由を添えて N/A / 未検証 と返してください。
このモードが指定されていないリクエストでは、以下の単独分析、検証、テスト追加の各手順を引き続き使用します。
判断フロー
1. 対象範囲を設定する
マニフェストとファイルの種類から、本番ファイルとテストファイルを特定します。範囲を絞った検索で見つからなかった場合は、パスを尋ねる前にカレントディレクトリ全体を広く確認してください。
| リクエスト | 対応 |
|---|---|
| 1つのコンポーネント、または名前の指定されたリスク | 対象範囲内のリスクが高い公開結果をすべて洗い出します。検証を求められていない限り、本番コードは編集しません |
| 小規模なコンポーネントの一般的なレビュー | 個別の結果を洗い出し、ソースとアサーションの対応付けから、呼び出し元から見えるギャップを報告します |
| 明示的なサバイバー検証 | 指定された結果をすべて洗い出します。検証対象のリスクが高い結果ごとに、代表的な観測可能候補を1つ実行し、Survived または Killed に分類します |
| 明示的な網羅的監査 | references/mutation-catalog.md を読み、意味のある候補をすべて分類します |
| 既存のテストスイートへのテスト追加 | まず分析します。検証済みのサバイバー、またはカバレッジがないことを実証できた結果に対してのみテストを追加します |
| 新しいテストスイートの作成 | ここで中止し、code-testing を使用します |
リクエストでリスクが指定されている場合は、コードを読む前に、そのリスクを公開結果の許可リストとして1行にまとめてください。同じメソッドがその結果を書き込むというだけで、その結果が対象範囲に含まれるわけではありません。
money math の場合、計算または返却される金額、レート、ティア/境界の選択、パーセンテージの基準/適用順序、下限/上限、丸めを対象に含めます。派生ブール値を含む金銭以外の状態判定、ID、書式設定は対象外です。プライベートコードは、許可された結果を追跡する場合に限り対象となります。
焦点を絞ったリクエストを、リポジトリ監査、計画成果物、ダッシュボードにまで拡大しないでください。慣れたフレームワークには、ソースとテストを直接使用してください。検出方法やアサーションの意味が不明な場合は、呼び出し元から提供された、または実行時に一覧表示された test-analysis-extensions カタログ内の該当言語ファイルを読みます。リファレンス専用ヘルパーを呼び出したり、インストールディレクトリを検索したりしないでください。見つからない場合は、その制約を明記し、ここに記載された固定のAPIとルールを使用してください。
2. ベースラインを 1 つ確立する
ソースのみのアドバイザリレビューでは、実行をスキップし、実証的な検証は未検証とラベル付けします。ユーザーが実行またはサバイバーの検証を要求した場合、あるいはテストでギャップを埋める場合には、ベースラインが必要です。既存の最も限定的なテストコマンドを 1 回実行します。プロジェクトのマニフェストから選択してください。Microsoft.Testing.Platform の実行ファイルでは dotnet run が必要になる場合があります。テストが実行されたことを確認してください。ビルドのみの出力で終了コード 0 であっても、グリーンではありません。この 1 回の試行でスイートを実行できない場合、アドバイザリレビューのためにランナーのトラブルシューティングを行ったり、代替コマンドを試したりしないでください。静的に続行し、すべての候補に unverified とラベル付けします。出力の欠如からプロジェクト構成の原因を推測しないでください。原因を挙げるのは、コマンドがそれを報告した場合のみです。
ランナーの出力が欠如していることは、実証的なミューテーションサバイバーの主張のみを制限します。ソースで証明された事実を不確実にするものではありません。到達するテストがない公開アウトカムは依然として No coverage であり、未変更の実装から導出された正確な期待値は依然として実用的です。ベースラインの制限は一度だけ述べ、すべての行にヘッジを付けるのではなく、静的なソース/アサーションの結論を直接示してください。
「テストはこれを検出するだろうか?」といったアドバイザリレビューでは、そのベースラインの後に実行を停止します。ソースからアサーションへのマッピングは、No coverage および Candidate survivor (unverified) にとって十分な証拠です。元の値が不明確な場合にのみ、未変更のコードを 1 回トレースまたは実行してください。ミューテーションを適用するのは、明示的な検証、網羅的な監査、またはテストでギャップを埋める場合のみです。
集中的なミューテーションの予算は、実行を制限するものであり、発見を制限するものではありません。すべての異なるアサートされていない公開アウトカムをインベントリに保持してください。
3. 公開される結果を一覧化する
各公開エントリーポイントについて、次の項目を整理します。
- 入力の区分:分類器の各分岐、複合条件、無効な入力と有効値に最も近いガード境界、デフォルトケース
- 各独立した観測結果:返されるフィールド/バリアント、例外の型、無効な入力の受け入れ、公開状態の遷移、外部への副作用
- 公開呼び出し元から観測される、プライベートヘルパーの組み合わせ、定数/レート、丸め、リトライ、キャンセル、エラー伝播
public input/sequence -> expected outcome -> existing assertion -> gap の形式を使います。
1つの戻り値フィールドに対するアサーションでは、別のフィールドはカバーされません。許可される結果を1つ確認しても、その拒否はカバーされません。
金額計算: 何もしない経路、すべてのレート/ティアと厳密な境界、演算順序、割合の基準または組み合わせ、下限/上限、丸めを一覧化します。公開結果を通じてプライベートヘルパーを追跡します。大まかな範囲だけを検証するテストでは、金額を厳密に特定できません。対応可能な金額計算の各行について、証拠となる入力を1つ導き、完全な呼び出しチェーンを通した元の厳密な結果を示します。その金額を示さずに、一般的な「厳密な金額をアサートする」という提案をしてはいけません。
順序付きガードとリトライ: 最小値未満で無効 | 最初の有効値 | 許可される最後の値またはリトライ可能な値 | 最初にブロックされる値 | それ以降にブロックされる値 を一覧化します。value >= limit のような上限ガードでは、limit - 1、limit、limit + 1 を使用します。最後の証拠値によって、value == limit への縮小を検出できます。受け入れられるエラークラスと拒否されるエラークラスをすべて一覧化します。型マッチングがポリモーフィックな場合は、完全一致の実行時型への縮小を検出できる、派生型の代表例を含めます。最初にブロックされる値のテストだけでは、最後に許可される値も、それ以降にブロックされる値も保護できません。
認可: 呼び出し元の観点から、関連する各 ID/ロール、リソースクラス、アクションを列挙します。未テストの false、拒否、ロールが変更されない結果は、いずれも独立したセキュリティ上の欠落です。拒否の結果を一覧化しないまま、許可される経路のバリエーションを分析してはいけません。公開インターフェースごとに確認します。
- 権限を返す API:ロール/リソースクラスの各区分と、返される各権限を個別に確認します。
- アクションをディスパッチする API:読み取り/書き込み/削除型の各アクション分岐、特に拒否を返すべき経路を確認します。
- ロール/状態遷移:受け入れ、拒否、無効、null、空の各入力と、状態が変わらないべき結果を含めます。
部分的にカバーされたヘルパーの別バリエーションよりも先に、まったくテストされていない公開分岐を実行します。アサートされていない高リスクの動作が5つを超える場合は、上位3〜5件を実行し、残りは No coverage または Candidate survivor (unverified) として明示したままにします。
実行しても、台帳の代わりにはなりません。変更または回答の前に、各無効入力、ガード境界、分類器の分岐、アクション、拒否を含む、必要な結果をすべて分類します。
完全性チェックポイント: 指摘事項を選ぶ前に、独立した各モード/フラグ、<= 0 ガードに対するゼロと負の両方、受け入れられるすべての例外クラス、そしてマッチングがポリモーフィックな場合は、受け入れられる派生例外の代表例を明示的に確認します。ガードが削除されてもフォールスルー後に同じ公開例外型が生成される場合、より細かな例外メタデータが確立された契約でない限り、同等とみなします。
4. 観測可能な候補のみを採用する
まず、各正確なミューテーションを、すべての引数を固定したうえで、既存のアサートされた各入力またはシーケンスに対して再生します。戻り値、例外、状態、副作用のいずれかが変化した場合は Likely killed であり、専用の単一目的のテストは不要です。ある入力におけるミュータントと、別の入力におけるオリジナルを比較してはいけません。
生存したものについては、実行または報告の前に目撃証跡を選び、witness -> original observation -> mutant observation と記載します。それを最小のテストで再利用します。完全な呼び出しチェーンをたどった後、最後の 2 つが公開的に異なる場合にのみ採用します。そうでなければ、区別可能な目撃証跡を選ぶか、破棄します。
除外するもの:
- 既存の式、条件、定数、戻り値、副作用を変更または削除するのではなく、ステートメントの挿入または並べ替えを必要とする編集。
- コンパイルできない編集。まだ参照されている宣言の削除を含みます。
- オーバーフロー動作、例外メッセージまたは
ParamNameメタデータ、その他現在のコントラクト、ソースの意図、テストによって確立されていないセマンティクス。 - 同じ結果、例外、状態、副作用にフォールスルーする、削除されたガードまたはショートサーキット。
- すべての公開入力シーケンスが同一に観測するプライベート表現の変更。たとえスイートがグリーンのままであっても。
- 提案されたテストがオリジナルとミュータントの両方に対してパスするミューテーション。
- 区別対象の入力で同じ値を返す境界編集。たとえば、
result < floor ? floor : resultを<=に変更するのは、両方の分岐がfloorを返すため等価です。 - ユーザーが指定しない限り、意味のある分岐、計算、副作用を持たない、単独の自動プロパティまたは些細な 1 行のラッパーまたは述語。
- 仮説上の将来の影響、生成されたコード、ログ出力またはフォーマットのみの変更、不可能な値、重複する構文バリアント。
直接的なアサーションの欠如は No coverage を証明しません。まず、公開呼び出し元と共有分岐を通じて既存のアサーションをたどってください。アサーションの欠如は、観測可能な候補を生存者にしますが、無害なミューテーションを意味のあるものにはしません。
5. 順位付けと分類
次の順に順位付けします。(1)セキュリティ上の拒否、金銭的な結果、エラー、状態変更、 (2)まったくアサートされていない公開結果、(3)弱いアサーションで到達する境界や正確な値、 (4)すでにアサートされている動作の別バリエーション。
変異や判定を選ぶ前に、インベントリを完成させてください。1つの試行がキルされたこと、例外の種類、または switch の分岐を確認しただけでは、同じ種類のほかの候補を確認したことにはなりません。
完成したインベントリに基づいて判定を選びます。
- Strong:主要な分岐と境界が保護され、残っているのは少数のバリデーションやデフォルトケースのバリエーションのみです。
- Mixed:意味のあるカバレッジはありますが、重要な結果のパーティションが少なくとも1つ保護されていません。
- Weak:重要な結果が広範に保護されていません。
バリデーションの未対応箇所が少数あるだけでは、バリデーションが明示されたリスクであるか、その未対応箇所がセキュリティ、データ、その他の契約上重要な動作を脅かす場合を除き、全体として広範なテストスイートを Mixed と判定しないでください。
インベントリが上記の Strong の基準を満たす場合は、Strong から始め、軽微な未対応箇所を挙げる前に、保護されている境界と二重のアサーションを明記してください。Mixed、「コアパスのみ」、またはリスクを過度に強調するダッシュボードから始めないでください。
既存のアサーションで残りの候補がキルされた場合、または信頼できる公開上のサバイバーが残っていない場合は、そこで終了してください。レポートを埋めたりスコアを計算したりするためだけに、すべての演算子を変異させないでください。
| 結果 | 意味 |
|---|---|
| Likely killed | 既存のアサーションが変更後の結果を観察します |
| Candidate survivor (unverified) | 観察可能な変更がアサートされていないように見えます。実行はしていません |
| Killed | 正確な観察可能な変異を実行し、関連するアサーションが失敗しました |
| Survived | 正確な観察可能な変異を実行し、テストは成功しました |
| No coverage | 公開結果に到達するテストがありません。サバイバーを捏造せず、欠けている分岐を報告してください |
| Equivalent | 公開上の観察結果に変化はありません。指摘事項から除外してください |
明示的な検証、網羅的な監査、またはテスト追加の依頼がない限り、変異は実行しないでください。カバレッジが明らかにないことを確認するために変異させないでください。明示的な検証では、対象範囲内のリスクが高い結果の種類ごとに、代表的な候補を1つ実行してください。別のガード、アクション分岐、エラー種別、または拒否がまだ未分類なのに、最初の1つか2つで終了しないでください。同等の構文上のバリエーションは除外してください。
6. 誤検出を起こさずに検証する
明示的な検証、網羅的な監査、またはテスト追加の依頼がある場合にのみ、このフェーズに進んでください。
- 候補を1つ適用し、差分が意図した式だけを変更していることを確認します。
- その候補をカバーする最も範囲の狭いテストを実行し、テストが実行されたことを確認します。成功した場合は Survived、関連するアサーションで失敗した場合は、その編集に限り Killed です。ビルド、テスト検出、インフラ、または無関係な失敗の場合、候補は Killed ではなく未検証のままです。
- 直ちに元に戻し、ソースとテストのベースラインがクリーンであることを確認します。
- テストが成功した後、公開上の反事実を再確認します。実行で証明できるのは、テストスイートが編集を見逃したことだけであり、その編集が動作を変えることではありません。動作に影響しない変異や観察不能な変異は除外してください。
ワークスペースに変異を残さないでください。報告する前に、アサートされていないリスクの高い結果をすべて、Survived、Candidate survivor (unverified)、No coverage、または記載を省略した Equivalent のいずれかに整理してください。信頼できる公開上の未対応箇所がなくなった時点で終了してください。ユーザーが網羅的な監査を依頼していない限り、内部の詳細を並べたりスコアを計算したりしないでください。
7. 要求された場合にのみギャップを埋める
- 焦点を絞ったテストを追加するのは、実行済みの Survived ミューテーション、または実証された No coverage の挙動に限ります。
- すでにカバー済みの挙動の別バリエーションをテストする前に、要求された範囲内の すべての明確なギャップをカバーしてください。
- 編集前に、サバイバーとテストのチェックリストを作成してください。作業を終える前に、 検証済みのすべてのサバイバーを追加したテストに対応付け、追加した各テストを 検証済みのサバイバーに対応付けてください。最終テストスイートが成功しただけでは、完全性の証明になりません。
- 要求された場合は、本番コードと既存のテストを変更しないでください。
- 構文上の変更ごとにテストを1つ追加するよりも、関連するミューテーションを排除できる、 挙動に焦点を当てたテストを1つ優先してください。
- 元のミューテーションを再適用し、新しいテストでそれを検出できることを証明してから、 ソースを復元し、対象を絞ったテストスイートを問題なく実行してください。
- フィクスチャまたはリポジトリに標準のミューテーション検証ツールが用意されている場合は、 テスト追加後にその正確なコマンドを実行し、成功結果を記載してください。 手作業で作成した代替ミューテーション、広範なテストスイートの成功、またはテスト数の増加は、 用意されたオラクルの代わりにはなりません。要求されたサバイバーすべてを焦点を絞ったテストに対応付け、 標準検証ツールが成功したら、作業を終了してください。テストを追加しても利点はありません。
- 既存のソースファイルまたはテストファイルを変更しないことが要求されている場合は、 保護対象の各ファイルを編集前のスナップショットとバイト単位で比較し、その証拠を報告してください。 テストを追加する前に、そのテストの判定材料が、関連する分岐、境界、または丸め結果において 既存のすべてのケースと異なることを証明してください。名目上は新しいテストでも、 既存のカバレッジと重複してはなりません。
出力要件
回答の詳しさは、依頼に合わせてください。
焦点を絞った分析または小規模な分析の場合は、次の内容を返してください。
-
判定を理由とともに一行で示してください。判定は Strong、Mixed、または Weak です。
-
Strong なテストスイートの場合は、その判定を裏付ける具体的な保護対象の境界、ガード、または対になる観測結果を挙げた、短い長所の説明を1文添えてください。
-
対応が必要な Survived、Candidate survivor (unverified)、または No coverage の結果ごとに、簡潔な表の行を1つ記載してください。行を追加する前に、依頼でリスクが指定されている場合は結果の許可リストを適用し、その後、観測可能な候補のルールを適用してください。いずれかのフィルターに通らない候補は省略してください。すべての高リスク結果を含め、公開される結果ごとに1行を使い、関連する低リスクのバリエーションのみまとめてください。
リスク 公開される結果 変更 結果/証拠 最小のテスト すべてのギャップに、他と区別できる判定材料と、具体的な最小テストが必要です。エラーパスのギャップには、 無効な入力と期待されるエラーまたは結果を明記してください。
-
Mixed または Weak なテストスイートの場合は、重要な挙動のうち検出できたものを挙げた、短い長所の説明を1文添えてください。
-
除外対象が指定されている場合は、生成コード、単純なコード、または無関係なコードのうち、意図的に対象外としたものを挙げた、短いスコープの説明を1文添えてください。
表の内容を文章で繰り返したり、破棄したミューテーション、ツールの実行順序、または進行中の推論を報告したりしないでください。
網羅的な監査の場合は、実行済みの Killed / Survived 件数と、静的分類である Likely killed / Candidate survivor (unverified) および No coverage / Equivalent の件数を分けてください。静的分析を実測の Killed/合計比率に含めないでください。所見はリスク別にまとめてください。
テストを追加した場合は、追加したテスト名、検出した検証済みミューテーション、および成功した最終コマンドを記載してください。
信頼性のルール
- 変更後の結果を検証しないテストに合格しても、ミューテーションは検出できません。
- カバレッジは振る舞いの区分ごとに評価します。1つの switch/三項演算子の分岐や複合入力を確認しても、隣接する分岐まで確認したことにはなりません。allow を確認しても deny の確認にはならず、read を確認しても write の確認にはなりません。また、入力によって呼び出し元から見える結果が異なる場合、null を確認しても empty や whitespace の確認にはなりません。ミューテーションの検出で確認できるのは、実行された編集箇所とパスに限られます。
- パブリックメソッド経由で呼び出されるプライベートヘルパーも対象に含まれます。
- エラーの意味は言語によって異なります。Rust では
?による伝播と panic の違いが観測可能な振る舞いです。C# では例外の型と、入力ガードが値を受け入れるか拒否するかが観測可能な振る舞いです。 - 厳密な数量や境界値の結果はすべて、変更前の実装または既存の厳密なアサーションと照合してください。確認できない場合は、数値を作り出さず、振る舞いの関係を記述してください。
- ミューテーションが検出されなかったという理由だけで、所見を高リスクと評価しないでください。
- 既存のテストスイートで既に保護されている振る舞いについて、重複するテストを推奨しないでください。
検証
- 対象範囲は依頼に見合ったものです
- 元のテストスイートに合格したか、静的解析のみの制約が明示されています
- 対象範囲内のリスクが高いパブリックな結果をすべて洗い出しています
- 元の実装とミュータントでは、呼び出し元から見える結果が異なります
- Survived と評価された結果はすべて実行済みです。未実行の候補には Candidate survivor (unverified) を使用しています
- 一時的なミューテーションはすべて元に戻しています
- 所見から、些細な変更、生成された変更、等価な変更を除外しています
- 推奨事項は、実証されたギャップのみを対象としています
- 対象範囲内の各パブリックなエントリーポイントの分岐と、許可される各例外型を明示的に説明しています
- 提供された正規のミューテーション検証ツールを実行して、その結果を報告しています。場当たり的な代替手段で置き換えていません