test-smell-detection について
学術的なテストスメル分類に基づいてテストコードを監査するエージェントスキルです。テストの信頼性や保守性を評価する開発者向けに、コード上の根拠を確認し、フレームワークの慣習に沿って問題と修正案を示します。
主な機能
- 01学術的な分類によるテストスメルの特定
- 02コード上の根拠とアサーションの確認
- 03フレームワークの慣習に沿った判定
- 04リスクと保守コストによる順位付け
- 05フレームワークに適した修正案
活用シーン
- 01ステージ済みまたは指定されたテストの監査
- 02誤って成功したり不安定になったりするテストの特定
- 03外部リソースに依存するテストの評価
- 04確認済みの問題に対する修正計画
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dotnet/ skills --skill test-smell-detectionインストール後、Claude Code で/test-smell-detectionを入力して読み込まれたか確認します。
同梱ファイルreferences/test-smell-catalog.md
詳細
テストの不吉な臭いの検出
学術的な分類体系、コード上の根拠、フレームワークのイディオムに合わせた評価、およびコードベースに適した修正方法を用いて、テストコードを監査します。
対象範囲
- ステージ済みまたは名前を指定されたテストのみを監査します。コードを求める前に現在のワークスペースを検索してください。関連するテストが見つからない場合に限り、ファイルが存在しないと判断してください。
- 判定が変わる場合に限り、本番コードを読みます。
- 不慣れなフレームワーク API については、呼び出し元から指定された、または実行時に一覧表示された
test-analysis-extensionsカタログ内の該当言語ファイルを読みます。スキルの呼び出し元は参照しません。見つからない場合は、ここに記載されたフレームワークとルールを使用し、参照資料が見つからないことを報告してください。インストール先のディレクトリは検索しないでください。 - 呼び出し元が19種類すべての不吉な臭いを求めている場合、引用を求めている場合、または下記の高シグナル群以外の不吉な臭いがコードに含まれている可能性がある場合は、完全なカタログを読みます。このファイルで回答できる限定的な質問の場合は、読み込まないでください。
監査ワークフロー
- ステージ済みテストを検索して読み、言語、フレームワーク、境界、および統合を示すマーカーを検出します。パスが指定されていない場合も、これを最初の作業とします。
- テストを読み、判定が変わる場合に限り本番コードのコンテキストを確認します。
- 候補ごとに、実行されるチェックを検証し、正式なカテゴリを選び、評価を調整してから重大度を割り当てます。立証された、カタログに含まれないテスト妥当性の欠陥は、別途報告してください。不吉な臭いとして再分類してはいけません。
- 誤った安心感や不安定さを招くリスクが高い順に、次いで保守コストの高い順に、確認済みの指摘事項を並べます。
- 対応可能な指摘事項ごとに、フレームワークに適合した置き換え案を提示します。別のエコシステムで .NET の用語や API を使用してはいけません。
重要度の高い判断
| 根拠 | 学術的な知見 | すべきこと | 絶対にしないこと |
|---|---|---|---|
if、switch、条件分岐を含むループ内でアサーションの挙動が変わる | 条件付きテストロジック | ケースを分割するか、パラメーター化します | 実行ランナーのループがあるという理由だけで、テーブル駆動テストやパラメーター化テストにフラグを立てます |
| テストが、宣言されていないファイル、ネットワークサービス、環境値、またはデータベースに依存している | ミステリーゲストまたはリソース楽観主義 | 依存関係を明示してハーメチックにし、完全なカタログを使って両者を区別します | 宣言された実リソースを使用しているという理由だけで、統合テストを非難します |
| 固定時間のスリープで、結果が出るのを待っている | スリーピーテスト | タイムアウトを設定して、条件を待機するかポーリングします | 統合テストであるという理由だけで、重要度を下げます |
| 実行可能なテストに、アサーション、期待される例外のマーカー、またはモックの検証がない | 不明テスト | 観察可能な結果をアサートします | 本文が空のテストを不明テストと呼びます。正式名称は空テストです |
| 非同期アサーション/コルーチンが作成されているものの、待機も返却もされていない | カタログに含まれない重大な誤検出 | 別途報告し、必要な await/return を示します | アサーション文は存在するため、不明テストに無理に分類します |
| 1つのテストで、関連のない本番環境の動作を多数検証している | 熱心なテスト | 動作ごとにテストを分けます | スコープを考慮せず、意図的なエンドツーエンドワークフローにフラグを立てます |
| 期待値の数値リテラルが、その場で意味を持たない | マジックナンバーテスト | ドメイン値に名前を付けるか、セットアップから導出します | 3つの項目を追加した直後の count == 3 に、すぐフラグを立てます |
アサーションが、契約として定められていない ToString、repr、description、または表示形式に依存している | 敏感な等価性 | 安定したフィールドをアサートするか、構造的マッチャーを使います | 書式化された文字列が明示的な契約であるテストにフラグを立てます |
| テストが期待される例外のフローを手動で管理している | 例外処理 | フレームワークの例外アサーションを使い、意味のある詳細を確認します | 例外を捕捉してアサートするテストが何も検証していないと断定します |
| 共有セットアップが、そのセットアップを使うテストに無関係な状態を作成している | 汎用フィクスチャ | 未使用の状態を削除するか、フィクスチャの範囲を絞ります。コストの低い状態は重要度を低くします | 共有されているという理由だけで、関連性のある共有セットアップを非難します |
| テストが無効化またはスキップされている | 無視されたテスト | すべてのスキップを報告しますが、追跡され理由も記録されたスキップは、説明のないスキップより重要度を低くします | 理由が妥当だからといってスキップを見逃したり、両者に同じ緊急度を付けたりします |
キャリブレーションルール
指摘を割り当てる前に、次のルールを適用してください。
- モック呼び出しの検証、スナップショット、単独の pytest
assert、PesterShould -Invoke、および期待する例外を検証する構文はアサーションです。 - リテラルアサーションやスナップショットアサーションによってカバレッジの不足が明らかになることはありますが、別の根拠がない限り、Unknown Test やその他のスメルには該当しません。
- アサーション文の数を数えてください。アサーションが1つだけなら、Assertion Roulette には該当しません。 メッセージがないことだけではスメルになりません。
- 同じメソッドをテストしていても、異なる振る舞い、境界値、状態をカバーしていれば Lazy Test ではありません。同等の経路が重複していることを確認してください。
- General Fixture には、共有されるライフサイクル状態が必要です。テスト内でローカルに繰り返しインスタンスを生成しても、それだけでは General Fixture にも Test Code Duplication にも該当しません。
- 公開 API が返す文字列は、プロダクションコードの文脈や要件から表示専用だと判断できない限り、観測可能な契約として扱ってください。補間だけでは Sensitive Equality には該当しません。
- Magic Number Test に該当するには、説明のないオラクル値が必要です。役割がその場で明らかで、アサート対象の振る舞いと無関係な通常のセットアップ値は指摘しないでください。
- Go のテーブル駆動サブテスト、pytest/JUnit/xUnit のパラメーター化、Jest/Vitest の
.each、RSpec のデータテーブル、Pester の-ForEach、Catch2 のSECTION/GENERATEは、それだけでは Conditional Test Logic に該当しません。 - Go の
if err != nil { t.Fatal(...) }は慣用的なアサーションの流れであり、Exception Handling ではありません。 - インテグレーションテストのマーカーは、宣言された外部リソースや複数ステップのフローを正当化しますが、固定時間のスリープやアサーションのない実行は正当化しません。
- インテグレーションテストでは、分岐カバレッジを判定する前にヘルパーファクトリーとリポジトリーの戻り値の型をたどってください。テストが、実際のヘルパーでは生成できないサブタイプや状態を条件に分岐している場合は、到達不能なアサーション経路を指摘し、誤った安心感につながる理由を説明してください。一般的な Conditional Test Logic のラベルを付けるだけで終わらせないでください。
- ローカルの一時ファイルも、定義上は Mystery Guest に該当します。隔離された作成とクリーンアップによって重大度は下がりますが、分類は変わりません。
- 名前に formatting が含まれていても、表示文字列が安定した契約であるとは限りません。Sensitive Equality の指摘を取り下げる前に、プロダクションコードの動作または要件で確認してください。
- メソッド名だけからスメルを推測しないでください。それを裏付ける文やフィクスチャ間の関係を示してください。
- テスト名だけから、カタログにない重大度の高い妥当性の欠陥を推測しないでください。そのテストが別のコンポーネントを呼び出すべきだと証明するプロダクションコードや明示的な契約がない場合、名前と本体の不一致は順位付けしない所見にとどまります。テストが壊れたプロダクション動作を黙って見逃す根拠にはなりません。
- Catch2 の
SECTIONとGENERATEはランナーによって制御されるケース展開であり、REQUIREは実際のアサーションです。疑わしい構文がこれらだけであれば、学術的なスメル判定は clean です。テストの振る舞いをより広くカバーできるという理由で、この判定を覆さないでください。 - キャリブレーション後に重大なスメルが残らない場合は、そのことを明確に述べてください。レポートの項目を埋めるために指摘を捏造してはいけません。
- void や、その他 await できない API に対して
awaitを提案しないでください。プロダクションの処理が同期的なら、スリープを削除し、すぐにアサートしてください。
重大度
重大度は、カタログの固定ラベルではなく、実証されたリスクに基づきます。
- 高: 動作が壊れていても黙ってテストを通過する可能性がある、非決定的な失敗を引き起こす、または実行されないアサーション経路を隠す場合。
- 中: 失敗の原因を曖昧にする、またはテストを不安定な詳細に結び付ける場合。
- 低: 理由のあるスキップや、範囲が広すぎる軽量なフィクスチャなど、主に保守上の負債である場合。
割り当てた重大度の理由を述べてください。周囲のテスト種別からそのパターンが意図的だと判断できる場合は、重大度を下げるか、指摘を省略してください。
出力契約
入力の規模に応じて、回答の内容を調整してください。
- ファイルが1~3個の場合は、判定と、重要度、 形式上のスメル、根拠、リスク、修正方法を含む簡潔な表を1つ提示してください。
- 大規模なテストスイートの場合は、件数と簡潔な優先順位を追加してください。ダッシュボード、説明、計画の間で指摘事項を重複させないでください。
- 修正内容を明確にする場合に限りコードを示し、変更のないセットアップは省略してください。
- 疑わしく見える可能性がある慣用表現に限り、簡潔な 該当なし を追加してください。
- 立証済みの、カタログに含まれない妥当性の欠陥は、学術的スメルの判定の後に記載してください。入力が問題なく、本番コードとの契約がない場合は、任意のカバレッジに関する所見に重要度を付けたり、それによって問題なしの判定を覆したりしないでください。
- 調査やカタログの読み込みについて説明せず、監査結果を直接返してください。
報告するすべてのスメルについて、正式な分類名、正確な場所、コードに基づく根拠、実用上のリスク、フレームワークに準拠した具体的な修正方法を示してください。
検証
- すべての指摘は、キーワードやメソッド名ではなく、コードによって裏付けられています。
- Unknown Test と Empty Test は区別されています。
- 無効化されているテストはすべて Ignored Test として扱われ、ローカルファイルへの依存はすべて Mystery Guest として扱われています。理由や、隔離可能にするための変更は重要度にのみ影響します。
- 報告前に、フレームワークの慣用表現と統合境界を確認しています。
- 問題のないテストや、疑わしく見えるものの妥当な慣用表現を、形式だけの指摘にしていません。
- 問題のないフレームワークの慣用表現を、命名や本番コードのコンテキストがないことを理由に、重要度の高い、カタログに含まれない指摘へ変えていません。
- 修正には対象フレームワークのAPIを使用し、検証対象の動作を維持しています。
- 確認したファイル、ビルド、テスト実行に関する記述は、実際に行った作業と一致しています。
コメント
Markdown 対応