テスト駆動開発 は何をしますか?
出力言語
デフォルトでは日本語(簡体字)を使用してユーザーとコミュニケーションし、テスト戦略、テスト説明、実装サマリーを日本語で記述します。ユーザーが明示的に他の言語を指定した場合や、既存のドキュメントの言語に別の取り決めがある場合は、その取り決めに従います。コード、コマンド、製品名、および原文を保持する必要がある引用は無理に翻訳しません。
Philosophy(基本哲学)
中核原理: テストは実装詳細ではなく、公開インターフェースを通して動作を検証すべきです。コードは完全に変更される可能性がありますが、テストは変更されるべきではありません。
良いテストは統合スタイルです。公開APIを通じて実際のコードパスを実行します。システムが 何をするのか を記述し、 どのようにするのか は記述しません。良いテストは仕様のように読めます。「ユーザーは有効なカートでチェックアウトできる」というテストは、どのような機能が存在するかを正確に示します。これらのテストは内部構造を気にしないため、リファクタリング後も耐えます。
悪いテストは実装に結合しています。内部のコラボレーターをモックしたり、プライベートメソッドをテストしたり、外部手段(データベースに直接クエリを実行するなど、インターフェースを使わない方法)で検証します。警告サイン:リファクタリングしても動作が変わっていないのにテストが壊れる場合。内部関数の名前を変更しただけでテストが失敗するなら、そのテストは動作ではなく実装をテストしています。
例については tests.md、モッキングガイドラインについては mocking.md を参照してください。
アンチパターン:水平スライス
すべてのテストを先に書き、その後で全実装を行ってはいけません。 これは「水平スライス」であり、REDフェーズを「全テストを書く」、GREENフェーズを「全コードを書く」と捉える誤った方法です。
これは 質の低いテスト を生み出します:
- 一括で書かれたテストは 実際の 動作ではなく 想像上の 動作をテストする
- ユーザー向けの動作ではなく、データ構造や関数シグネチャなど 物の形 をテストすることになる
- テストは実際の変更に対して鈍感になる。動作が壊れてもテストがパスし、動作が正しくてもテストが失敗する
- 実装を理解する前にテスト構造にコミットしてしまい、視野が狭くなる
正しいアプローチ: トレーサーブレットによる垂直スライス。1テスト→1実装→繰り返し。各テストは前のサイクルで学んだことに基づいて書かれます。コードを書いたばかりなので、どの動作が重要でどのように検証すべきかが正確にわかります。
誤り(水平):
RED: test1, test2, test3, test4, test5
GREEN: impl1, impl2, impl3, impl4, impl5
正しい(垂直):
RED→GREEN: test1→impl1
RED→GREEN: test2→impl2
RED→GREEN: test3→impl3
...
ワークフロー
1. 計画
コードベースを探索する際には、CONTEXT.md(存在する場合)を読んで、テスト名とインターフェース用語がプロジェクトのドメイン言語と一致するようにし、触れる領域のADRも尊重します。
コードを書く前に:
- 必要なインターフェース変更についてユーザーと確認する
- テストすべき動作についてユーザーと確認する(優先順位付け)
- インターフェース境界が不明瞭な場合、コードベース設計原則を用いて深いモジュールの機会を特定する。ユーザーが明示的に要求しない限り、別のスキルを自動的に呼び出さない。
- テストする動作をリストアップする(実装手順ではなく)
- 計画についてユーザーの承認を得る
質問例:「公開インターフェースはどのようにすべきですか?テストする上で最も重要な動作はどれですか?」
すべてをテストすることはできません。 ユーザーと正確にどの動作が最も重要かを確認してください。すべてのエッジケースではなく、クリティカルパスと複雑なロジックにテストの労力を集中させてください。
2. トレーサーブレット
システムについて 1つのこと を確認する 1つのテスト を書きます:
RED: 最初の動作のテストを書く → テスト失敗
GREEN: パスする最小限のコードを書く → テスト成功
これがトレーサーブレットです。エンドツーエンドでパスが機能することを証明します。
3. インクリメンタルループ
残りの各動作に対して:
RED: 次のテストを書く → 失敗
GREEN: パスする最小限のコード → 成功
ルール:
- 一度に1テストずつ
- 現在のテストにパスするコードだけを書く
- 将来のテストを先取りしない
- テストは観測可能な動作に集中させる
4. リファクタリング
すべてのテストがパスしたら、リファクタリング候補 を探します:
- 重複の抽出
- モジュールの深化(複雑さをシンプルなインターフェースの背後に移動)
- SOLID原則を自然な形で適用
- 新しいコードが既存コードについて何を明らかにするかを検討
- リファクタリングの各ステップ後にテストを実行
RED状態ではリファクタリングしないでください。 必ず先にGREENにしてください。
各サイクルのチェックリスト
[ ] テストは動作を記述しており、実装を記述していない
[ ] テストは公開インターフェースのみを使用している
[ ] テストは内部リファクタリング後も生き残る
[ ] コードはこのテストに対して最小限である
[ ] 推測による機能追加がない