tdd について
コーディングエージェント向けの TDD スキルです。公開インターフェースで振る舞いを検証し、テストを一つずつ進め、GREEN の後にリファクタリングします。
主な機能
- 01公開インターフェース経由のテスト
- 02段階的な RED–GREEN サイクル
- 03振る舞いに基づくテスト計画
- 04GREEN 後のリファクタリング
- 05フェイクと接点に関するローカル規則
活用シーン
- 01ユーザーに見える振る舞いのテスト計画
- 02小さなテストサイクルでの機能実装
- 03実装詳細との結合の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dmmulroy/ skills --skill tddインストール後、Claude Code で/tddを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
mocking.mdrefactoring.mdtests.md詳細
テスト駆動開発
哲学
中核となる原則:テストでは、実装の詳細ではなく、公開インターフェイスを通じて動作を検証します。コードは全面的に変更してもかまいませんが、テストは変えるべきではありません。
良いテストは、統合テストのように、公開 API を通じて実際のコードパスを実行します。システムが「どのように」動作するかではなく、「何を」するかを記述します。良いテストは仕様書のように読めます。「ユーザーは有効なカートでチェックアウトできる」とあれば、どのような機能があるのかが明確にわかります。内部構造を気にしないため、こうしたテストはリファクタリング後も機能します。
悪いテストは、実装と密結合しています。内部の連携先をモックしたり、プライベートメソッドをテストしたり、インターフェイスを使わずデータベースに直接問い合わせるなど、外部の手段で検証したりします。警告すべき兆候は、リファクタリングで動作は変わっていないのにテストが失敗することです。内部関数の名前を変更してテストが失敗するなら、そのテストが検証していたのは動作ではなく実装です。
例については tests.md、モックのガイドラインについては mocking.md を参照してください。
アンチパターン:水平分割
テストをすべて先に書いてから、実装をすべて行ってはいけません。 これは「水平分割」です。RED を「テストをすべて書くこと」、GREEN を「コードをすべて書くこと」と捉えるやり方です。
この方法では質の悪いテストが生まれます。
- まとめて書いたテストは、実際の動作ではなく、_想像上の_動作をテストします
- ユーザーから見える動作ではなく、データ構造や関数シグネチャなど、ものの_形_をテストすることになります
- テストが実際の変更に反応しなくなり、動作が壊れても成功し、動作に問題がなくても失敗します
- 実装を理解する前にテスト構造を確定してしまい、見通しの先を急ぎすぎます
正しいアプローチ:トレーサーバレットによる垂直分割です。テストを1つ書き、実装を1つ行い、これを繰り返します。それぞれのテストは、前のサイクルで得た知見を反映します。コードを書いたばかりなので、重要な動作とその検証方法を正確に把握できます。
WRONG (horizontal):
RED: test1, test2, test3, test4, test5
GREEN: impl1, impl2, impl3, impl4, impl5
RIGHT (vertical):
RED→GREEN: test1→impl1
RED→GREEN: test2→impl2
RED→GREEN: test3→impl3
...
ワークフロー
1. 計画
コードベースを調べるときは、テスト名やインターフェイスの用語をプロジェクトのドメイン言語に合わせ、変更する領域の ADR に従うため、CONTEXT.md が存在すれば読みます。
コードを書く前に、次のことを行います。
- 必要なインターフェイスの変更についてユーザーに確認する
- テストする動作とその優先順位についてユーザーに確認する
- ディープモジュール(小さなインターフェイスと深い実装)にできる箇所を特定する — 設計とテスト容易性の基準については
../coding-standards/SKILL.mdを参照してください - 実装手順ではなく、テストする動作を列挙する
- 計画についてユーザーの承認を得る
次のように尋ねます。「公開インターフェイスはどのような形にするべきですか?テストするうえで、最も重要な動作はどれですか?」
すべてをテストすることはできません。 最も重要な動作をユーザーに確認してください。考えられるすべてのエッジケースではなく、重要なパスや複雑なロジックのテストに注力します。
2. トレーサーバレット
システムについて1つのことを確認するテストを1つ書きます。
RED: Write test for first behavior → test fails
GREEN: Write minimal code to pass → test passes
これがトレーサーバレットです。パスがエンドツーエンドで機能することを確認します。
3. 段階的なループ
残りの動作について、次を繰り返します。
RED: Write next test → fails
GREEN: Minimal code to pass → passes
ルール:
- 一度にテストは1つだけ
- 現在のテストに合格するのに必要なコードだけを書く
- 将来のテストを先回りしない
- 観測可能な動作に焦点を当ててテストする
4. リファクタリング
すべてのテストに合格したら、リファクタリング候補を探します。
- 重複を抽出する
- モジュールを深くする(複雑さをシンプルなインターフェイスの背後に移す)
- 自然な箇所に SOLID 原則を適用する
- 新しいコードから既存のコードについてわかることを検討する
- リファクタリングの各ステップ後にテストを実行する
RED の間は絶対にリファクタリングしないでください。 まず GREEN にします。
サイクルごとのチェックリスト
[ ] Test describes behavior, not implementation
[ ] Test uses public interface only
[ ] Test would survive internal refactor
[ ] Code is minimal for this test
[ ] No speculative features added
ローカルでの上書き(dmmulroy/skills)
このスキルは mattpocock/skills からベンダー提供されています。このリポジトリでは、
../coding-standards/SKILL.md が信頼できる情報源であり、両者が食い違う場合は
mocking.md より優先されます。
- モジュールのパッチ適用 API(
vi.mock、jest.mock)やメソッドスパイ API (vi.spyOn、jest.spyOn)は使用しないでください。代わりに、実際のシームを通じて動作を置き換えてください (コンストラクターに注入する依存関係、Effect サービス/レイヤー、記録用フェイクアダプター、 ローカルデータベース、ランタイムバインディング)。 - システム境界であっても、モックより、本番環境のシームを通じて提供する記録用フェイクを優先してください。
- リスクに応じた証拠を示し、その根拠が特定のデータベースやランタイムに依存する場合は、代表的なものを使用してください。