tdd について
公開インターフェースと観察可能な振る舞いをテストするための、TDD ガイドです。テストと実装を一つずつ進める方法を提案し、計画、リファクタリング、各サイクルのチェック項目を示します。
主な機能
- 01公開インターフェースの振る舞いをテスト
- 02段階的なレッド・グリーンサイクル
- 03水平スライスのアンチパターンを回避
- 04計画とリファクタリングの手順
- 05各サイクルのチェックリスト
活用シーン
- 01段階的な TDD ワークフローの計画
- 02テストと実装詳細の結び付きを軽減
- 03リファクタリング時の振る舞い確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ryanravn/ ryra-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. 計画
コードベースを調査する際は、テスト名とインターフェースの用語がプロジェクトのドメイン用語に合うよう、CONTEXT.md(存在する場合)を読み、作業対象領域の ADR を尊重してください。
コードを書く前に、以下を行います。
- 必要なインターフェースの変更についてユーザーに確認する
- テストする動作(優先順位を含む)についてユーザーに確認する
- ディープモジュール(小さなインターフェースと深い実装)の機会を特定する — 用語とテスト容易性の確認には
/codebase-designスキルを実行する - テストする動作(実装手順ではない)を一覧にする
- 計画についてユーザーの承認を得る
次のように尋ねます。「公開インターフェースはどのような形にすべきですか?テストで最も重要な動作はどれですか?」
すべてをテストすることはできません。 どの動作が最も重要か、ユーザーに具体的に確認してください。考えられるすべてのエッジケースではなく、重要なパスと複雑なロジックにテストの労力を集中させます。
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