test-suite-doctor は何をしますか?
肥大化したテストスイート(例:2000件以上のテスト、その多くがAI生成のスロップ)を、実際のカバレッジを測定して保持しながら、小さく高品質なスイートに縮小します。
ハードルール
- 意見より指標。
collectとminimizeで計画を作成する前に、テスト削除を提案してはいけません。テストコードを読んで「役に立たない」と判断しても証拠にはなりません。些細に見えるテストが唯一のブランチカバレッジになることもあります。 - 計画は提案であり、最終判断ではない。 カバレッジはAPIコントラクト、文書化された回帰テスト、プロパティ不変条件を考慮できません。削除候補はすべて、削除前にレビュー(ステップ3)を受ける必要があります。
- ブランチで作業する。 テスト削除前に、ワーキングツリーがクリーンであることを確認し、ブランチ(例:
test-doctor/minimize)を作成します。ダーティツリーまたはデフォルトブランチでテストを削除してはいけません。 - 検証するか、元に戻す。
verifyが終了コード0を返すまで作業は完了しません。失敗した場合は、報告されたギャップに対するテストを再生成して再検証するか、削除したテストを復元します。
要件確認(最初に行うこと)
- Node.js 22 以上、およびローカルインストールされた Vitest または Jest を使用する package.json が必要です(
node <skill-root>/dist/cli.mjs collect --help)。 - カバレッジプロバイダがインストールされている必要があります(Vitest:
@vitest/coverage-v8;Jestには組み込み済み)。不足している場合は、開発依存関係としてインストールするよう提案します。 - ミューテーション検証には、対象リポジトリで
@stryker-mutator/coreが設定されている必要があります。これはオプトインであり、促されずにインストールしてはいけません。 - 開始前にテストスイートがグリーン(成功)している必要があります。ベースライン実行で障害が報告された場合は、ユーザーに通知し、最小化前にどのように対処するか合意を得てください(失敗するテストは信頼できないカバレッジを提供します)。
以下のすべてのコマンドは対象リポジトリのルートから実行します。$SKILL はこのスキルのディレクトリです。生成物は .test-doctor/ に配置されます(.gitignore への追加を推奨)。
ワークフロー
1. 計測(スクリプト — 常に最初)
node "$SKILL/dist/cli.mjs" collect --cwd .
テストランナーを検出し、全スイートを1回実行してカバレッジベースラインを取得した後、各テストファイルを個別に実行してカバーした行・ブランチと実行時間を記録します。.test-doctor/report.json を書き出します。
- デフォルトの粒度はテストファイル単位です(テスト単位の分離は正確ですが、すべてのテストを個別に実行するため、小規模または既に縮小されたスイート、または
--filterでスコープ指定した場合のみ--granularity testを提供してください)。 - 2000件のテストスイートでは時間がかかるため、バックグラウンドで実行し、進捗を報告します。レポート内の
collectionErrorsを真剣に受け止めてください。これらのエラーはデフォルトで最小化をブロックします。ユーザーが明示的に--keep-unmeasuredを選択した場合、影響を受けるすべてのユニットは強制的に保持され、計画は信頼できないとマークされます。 --filterは意図的にスコープされたベースラインを作成します。収集、最小化、検証は一致するテストファイルのみに適用されます。すべての推奨事項でそのスコープを明示してください。これはリポジトリ全体の保証ではありません。
2. 最小化(スクリプト)
node "$SKILL/dist/cli.mjs" minimize --coverage-floor 0.97 --target-count 200
貪欲重み付き和選択:カバレッジフロアを満たすまで、実行時間1ミリ秒あたりに新しくカバーする行・ブランチが最も多いユニットを繰り返し保持します。.test-doctor/plan.json と、保持・削除された各ユニットの正当性を記した人間が読める .test-doctor/plan.md を書き出します。
- ユーザーが指定しない場合はしきい値を尋ねてください。デフォルトは行カバレッジフロア0.97、ブランチフロアなし、ターゲット数なしです。
--helpですべての調整項目を表示できます。 - 既知の契約テストや回帰テストは事前に強制保持します。
--keep 'contract' --keep 'regression'(ユニットIDに対する正規表現)。 - 計画の
warnings配列に注意してください。例えば、フロアに到達できない、ターゲット数より多くのユニットが必要になるなどの警告です。これらをユーザーにそのまま伝えてください。
3. レビュー(判断 — あなたの作業)
references/slop-patterns.md を読み、plan.md の削除リストをレビューします。
- カバレッジでは見えない振る舞いを検証するテストを救出します。公開APIコントラクト、課題/バグIDを参照する回帰テスト、コンシューマーが依存するエラーメッセージの文言、プロパティ/不変条件チェックなどです。計画を手動編集する代わりに、追加の
--keepパターンで minimize を再実行します。 - 残りが安全な削除であることを確認し、スロップパターンごとに分類して、各テストがなぜ削除されるのかをユーザーに示します(パターンファイルにカタログがあります)。
次に、references/quality-rules.md に照らして保持リストをレビューします。怪しい保持テスト(モックのモック、トートロジー、空のスナップショットなど)はその場で書き換えます。カバレッジは獲得しますが、きれいに獲得すべきです。
このレビューが完了した後にのみ、ブランチ上で削除されたテストファイル/ケースを削除します。ユニットがすべて削除された場合はファイル全体を削除し、ファイル内の一部のテストのみが削除される場合はファイルを編集します(テスト粒度)。
4. 再生成(判断 — あなたの作業)
verify を一度実行し(失敗する可能性があります)、カバレッジギャップレポートを取得し、verify がリストする最も影響の大きいソースファイルに対して新しいテストを記述します。references/quality-rules.md に従います:AAA構造、振る舞い駆動の名前、テストごとに1つの振る舞い、モックは外部境界のみ。3つの浅いテストよりも、実際のユーザーに見える振る舞いをカバーする1つの強力なテストを優先します。
5. 検証(スクリプト — 完了のゲート)
node "$SKILL/dist/cli.mjs" verify --coverage-floor 0.97
# オプション、クリティカルモジュールのみ(低速):
node "$SKILL/dist/cli.mjs" verify --mutation --mutate "src/billing/**/*.ts" --mutation-floor 80
スイートを再実行し、グリーンであること、およびベースラインに対する行保持率がフロアを満たすことを要求します。終了コード0 = 完了、1 = 修正して再実行(テスト再生成または削除の復元)、2 = 環境の問題、停止して報告。ミューテーションテストはモジュールごとのオプトインであり、低速のため、ユーザーがクリティカルと呼ぶモジュールに対してのみ提供します。
バージョン2ではカバーされたソース、ランナー設定、ロックファイル、ランナー、カバレッジプロバイダをベースラインに記録します。verify が来歴のずれを報告した場合は、新しいベースラインを収集します。--allow-provenance-drift は明示的なユーザー同意がある場合のみ使用し、結果の判定は信頼できないと報告します。レガシー v1 ベースラインも同様に、明示的な --allow-legacy-baseline エスケープハッチが必要です。
報告
ユーザーに要約します:元のユニット数 → 後のユニット数、行/ブランチ保持率、実行時間 前 → 後、見つかったスロップパターン(件数付き)、削除リストから救出したテストとその理由、再生成したテスト、最終的な verify の判定。完全な監査証跡として plan.md へのパスを含めます。
失敗モード
- ランナーが検出されない/曖昧 → CLI は終了コード2でガイダンスを表示します。
--runnerまたは--cwdを指定します(モノレポ:パッケージごとに実行)。 - 収集が不完全 → 個別の失敗を修正します。単に計画を通すためにフィルタリングしてはいけません。フィルタは宣言されたベースラインスコープを変更します。
--keep-unmeasuredは保守的なエスケープハッチです。 - 再生成後も verify が失敗し続ける → 約3回の試行でループを停止し、残ったギャップをファイルごとに提示し、ユーザーにフロアを下げるかテストを維持するかを決定させます。
- スイートが開始前にレッドだった → 無関係な失敗を黙って「修正」せず、報告し、最初にスコープについて合意します。