codeprobe-testing について
テスト品質とカバレッジを監査するコードレビュー用スキルです。開発者がテストの不足、設計上の問題、モックの不適切な使用、脆弱なテストデータを確認できます。
主な機能
- 01テスト不足とカバレッジ漏れの検出
- 02アサーションとテスト構成の確認
- 03モックの不適切な使用の検出
- 04脆弱なテストデータと依存関係の指摘
活用シーン
- 01リリース前のテストレビュー
- 02未テストのエラー・認可パスの特定
- 03脆弱なテストや実装依存の低減
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ machineroom-dev/ codeprobe --skill codeprobe-testingインストール後、Claude Code で/codeprobe-testingを入力して読み込まれたか確認します。
詳細
スタンドアロンモード
オーケストレーター経由ではなく直接呼び出された場合は、まず次の手順を実行する必要があります。
- 出力仕様、実行モード、制約を確認するため、
../codeprobe/shared-preamble.md(ユーザーのプロジェクトではなく、この SKILL.md の場所を基準に、兄弟ディレクトリにあるcodeprobeスキルディレクトリを解決してください)を読みます。 - プロジェクトの技術スタックに基づいて、該当する参照ファイルを
../codeprobe/references/(同じ方法で解決)から読み込みます。 - ユーザーから別の指定がない限り、
fullモードをデフォルトとします。
テスト品質・カバレッジ監査
対象範囲
このサブスキルでは、次の 6 つのカテゴリにわたって、テスト品質とカバレッジの問題を検出します。
- テストの不足 — 対応するテストがない公開メソッド、テストされていない重要なビジネスロジック。
- テストの不適切なパターン — アサーションがないテスト、実装の詳細を検証するテスト、壊れやすいテスト。
- テスト構成 — Arrange-Act-Assert の区分がない、命名が不適切、過剰な数の項目をテストしている。
- モックの誤用 — テスト対象システムをモックする、モックがモックを返す、過剰なモック。
- カバレッジのギャップ — エラー処理、認可ロジック、エッジケースのテストがない。
- テストデータ — ハードコードされた ID、壊れやすいフィクスチャ、環境に依存するテスト。
検出対象外
- 単純なゲッター/セッターや純粋な DTO のテスト不足 — これらのテストは、意味のあるカバレッジにつながらず、テストの負担を増やします。
- フレームワークが生成するテストのひな型で、空でも明らかに足場として用意されたもの(例:Laravel の
ExampleTest.php、Create React App のApp.test.js) — 放置されたテストではなく、出発点です。 - 意図的にユニットテストの規約に従っていない統合テスト/E2E テストのスイート — テストレベルが異なれば、設計上の制約も異なります。
- テストの実行速度 — このサブスキルでは、実行時のパフォーマンスではなく、テスト設計の品質を評価します。
vendor/、node_modules/、その他の依存関係ディレクトリにあるテスト。
検出手順
重大度の上限
このサブスキルの検出結果を Critical に分類してはなりません。 重要なビジネスロジックのテスト不足であっても、保守性とリスクの問題(Major)であり、本番環境の不具合が確認されたことを意味するものではありません。このサブスキルで割り当てられる重大度の上限は Major です。各検出テーブルの重大度列に記載された内容に厳密に従い、それを超える重大度に引き上げてはなりません。
テストの不足
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|---|---|---|
TEST | 対応するテストがない公開メソッド | ソースディレクトリから、公開クラスメソッドを検索します。それぞれについて、対応するテストファイル/メソッドが存在するか確認します。テストファイルの命名規則には、file_stats.py のパターンに一致する test_、_test.、.test.、Test[A-Z]、spec_、_spec.、.spec. を使用します。 | Major |
TEST | テストされていない重要なビジネスロジック | 支払い、認証、認可、注文処理、データ変更を扱うクラス/メソッドを特定します。これらに専用のテストカバレッジがあるか確認します。 | Major |
TEST | 未対応のエッジケース | メソッドのテストが存在する場合、null/空の入力、境界値(0、-1、最大値)、エラーケース、正常系をカバーしているか確認します。正常系のみをテストしているメソッドを報告します。 | Minor |
テストの不吉な臭い
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|---|---|---|
TEST | アサーションのないテスト | テストメソッド内でアサーションの呼び出し(assert、expect、should、verify)を検索します。コードを実行しているものの、結果を一度もアサートせず、「例外がスローされないこと」だけを確認しているテストメソッドを検出します。 | Major |
TEST | 実装の詳細をテストするテスト | すべての依存関係をモックし、結果ではなく呼び出し順序や回数だけを検証するテストです。動作が変わらなくても、内部実装の変更で失敗するテストも該当します。過剰な ->expects()->method()->with() のチェーンや、戻り値を確認しない toHaveBeenCalledWith を探します。 | Minor |
TEST | 外部状態に依存する脆いテスト | テスト内で設定されていないデータベースの状態、ファイルシステムのパス、ネットワーク呼び出し、またはモックされていないシステム時刻に依存するテストです。テスト内の生の SQL、file_exists() のチェック、モックなしの HTTP 呼び出しを探します。 | Minor |
TEST | 実行順序に依存するテスト | 単独実行では成功するものの、まとめて実行すると失敗する(またはその逆の)テストです。テストメソッド間で共有される変更可能な状態を探します。例:テストで変更されるクラスレベルのプロパティ、クリーンアップされないデータベースレコード。 | Major |
テストの構成
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|---|---|---|
TEST | Arrange-Act-Assert の分離が不十分 | セットアップ、実行、アサーションが明確に分けられず、入り交じっているテストメソッドです。1つのテスト内に、実行とアサーションのサイクルが複数あるケースも該当します。 | Minor |
TEST | シナリオを説明していないテスト名 | test1、testFunction、it_works のようなテストメソッド名や、入力条件と期待される結果を説明していない汎用的な名前を検出します。良い例:test_empty_cart_returns_zero_total。悪い例:testCalculate。 | Minor |
TEST | 1つのテストで多くのことをテストしている | 関連のない結果に対するアサーションが5つ以上ある、または複数のシナリオを連続してテストするテストメソッドです。対象を絞ったテストに分割する必要があります。 | Minor |
モックの乱用
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|---|---|---|
TEST | テスト対象システムのモック化 | テストで、テスト対象クラスのモックまたは部分モックを作成しています。テスト対象は実際のコードではなくモックです。$this->createPartialMock(ClassName::class) や、sut がテスト対象クラスである場合の jest.spyOn(sut, 'method') を探します。 | Major |
TEST | モックが別のモックを返す | モックオブジェクトが別のモックオブジェクトを返すように設定され、深いモックチェーンが作られています。$mock->method('getUser')->willReturn($userMock) の後に、$userMock->method('getProfile')->willReturn($profileMock) が続くケースです。 | Major |
TEST | 過剰なモック化によって常にテストが成功する | すべての依存関係がモック化され、コードが期待する値をモックがそのまま返すため、テストが同語反復になっているケースです。実装ロジックを変更しても、結果をモックが決めるためテストが成功し続けます。 | Minor |
カバレッジの不足
| ID Prefix | 検出対象 | 検出方法 | 重大度 |
|---|---|---|---|
TEST | エラー/例外の経路に対するテストがない | try/catch ブロックやエラー処理を含むメソッドで、テストが成功経路しかカバーしていません。catch/エラーの分岐を実行するテストがありません。 | Minor |
TEST | 認可ロジックに対するテストがない | アクセスを制御するコード(権限チェック、ポリシーメソッド、ゲート定義、ミドルウェアによる認可)に、専用のテストがありません。 | Major |
TEST | エッジケースのテストがない | 配列/コレクションを扱う関数に、空の入力をテストするケースがありません。数値関数に、ゼロ、負の値、境界値をテストするケースがありません。文字列関数に、空文字列、Unicode、非常に長い入力をテストするケースがありません。 | Minor |
テストデータ
| ID プレフィックス | 検出対象 | 検出方法 | 重大度 |
|---|---|---|---|
TEST | 衝突する可能性のあるハードコードされた ID | ファクトリーで生成した値ではなく、ハードコードされた数値 ID($userId = 42、id: 1)を使用しているテストです。並列テストの実行時や、シードデータとの間で衝突します。 | 軽微 |
TEST | 壊れやすいファクトリー/フィクスチャの設定 | ファクトリー/フィクスチャ/ビルダーを使用せず、複数のテストで重複する複雑なインラインデータ設定を含むテストです。 | 軽微 |
TEST | 特定のデータベース状態に依存するテスト | テストのセットアップでレコードを作成せずに、特定のレコードがデータベースに存在すると想定するテストです。シーダーや、それ以前に実行されたテストに依存します。 | 軽微 |
ID プレフィックスと修正プロンプトの例
すべての検出結果には TEST- プレフィックスを使用し、TEST-001、TEST-002 のように連番を付けます。
修正プロンプトの例
- "
OrderService@calculateTotalのテストを作成してください。空のカート(0 を期待)、単一の商品、複数の商品、割引のある商品をカバーします。テストデータにはOrderFactoryを使用してください。tests/Unit/Services/OrderServiceTest.phpに配置してください。" - "
tests/Feature/AuthTest.php:25のテストtest_user_can_loginにはアサーションがありません。ログインエンドポイントを呼び出すだけです。assertStatus(200)、assertAuthenticated()、assertJsonStructure(['token'])のアサーションを追加してください。" - "
tests/Unit/PaymentServiceTest.php:40では、モックの連鎖が深くなりすぎています。ネストされたモックの戻り値の代わりに、ゲートウェイインターフェースを実装し、予測可能な応答を返す具象クラスFakePaymentGatewayを作成してください。" - "並列テストの実行時にテストが衝突しないよう、
tests/Feature/OrderTest.php:15のハードコードされたユーザー ID42をUser::factory()->create()->idに置き換えてください。"
コメント
Markdown 対応