tdd について
tdd は、新機能、バグ修正、リファクタリング、動作変更にテスト駆動開発を適用するスキルです。意図した理由で失敗するテストを先に確認し、最小限の実装で通した後、新しい動作を加えずにリファクタリングします。
主な機能
- 01本番コードより先に動作テストを作成
- 02意図した理由でテストが失敗するか確認
- 03合格に必要な最小限のコードを追加
- 04実装後に関連テストを実行
- 05テストの成功を保ってリファクタリング
活用シーン
- 01テスト先行のサイクルで新機能を開発
- 02バグ修正に回帰テストを追加
- 03テストを維持しながら動作をリファクタリング
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ gusen1453/ creed --skill tddインストール後、Claude Code で/tddを入力して読み込まれたか確認します。
詳細
TDD
出力言語: 回答と成果物は、ユーザー自身の言語で書いてください(リポジトリの履歴ではなく、ユーザーのメッセージに合わせてください)。
概要
まずテストを書きます。失敗することを確認します。通過する最小限のコードを書きます。リファクタリングします。
基本原則:テストが失敗するのを確認していないなら、そのテストが正しい対象をテストしているかどうかは分かりません。
必須の併用スキル: 何を入力し、何を検証し、何をモックするかには test-design を使用してください。このスキルが定めるのはリズムだけです。形式だけの RED テストも引き続き禁止です。見せかけのテストが失敗しても、何の証明にもなりません。
使用する場面
常に: 新機能、バグ修正、リファクタリング、動作の変更。
例外(まず人間に確認してください): 使い捨てのプロトタイプ、生成コード、動作を伴わない純粋な設定。
「今回だけ TDD を省略しよう」と考えていますか? 立ち止まってください。それは自己正当化です。
鉄則(交渉不可)
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
テストより先にコードを書きましたか? 削除してください。最初からやり直します。
例外はありません:
- 「参考用」として残さない
- テストを書きながら「調整」しない
- 見ない
- 削除とは、削除することです
文面に反することは、精神にも反することです。
ワークフロー(呼び出されたとき)
「tdd を使って…」と宣言してから、サイクルの各ステップにつきTODO を1つ作成します。
- RED — 失敗する動作テストを1つ書きます(test-design を適用:契約、絞り込んだアサーション、手書きの
expected) - RED を確認 — テストを実行し、正しい理由で失敗することを確認します(機能不足であり、タイプミスやエラーではない)
- GREEN — 通過に必要な最小限の本番コードを書きます
- GREEN を確認 — テストを実行し、関連するテストがすべて通過し、出力に問題がないことを確認します
- リファクタリング — 整理します。テストを通過した状態に保ち、新しい動作を追加しません
- 繰り返す — 次の動作に取り組み、次の RED に進みます
後からバグが見つかりましたか? まず失敗する再現テストを書き、同じサイクルを実行してください。
Red → Green → Refactor
RED — 失敗するテストを1つ書く
動作は1つだけにします。明確な名前(役割 + シナリオ + 期待値)を付けます。IO の都合で Fake/Recording が必要な場合を除き、実際のコラボレーターを使います(test-design を参照)。
test("retries failed operations 3 times", async () => {
let attempts = 0
const operation = () => {
attempts++
if (attempts < 3) throw new Error("fail")
return "success"
}
expect(await retryOperation(operation)).toBe("success")
expect(attempts).toBe(3)
})
悪い例:曖昧な名前、モックの呼び出し回数だけを検証するアサーション、本番ロジックで計算した expected。
RED を確認 — 必須
対象のテストを実行します。次の点を確認してください。
- 失敗する(タイプミスや import の問題によるエラーではない)
- 失敗メッセージが不足している動作に対応している
- すぐに通過した場合 → 既存の動作をテストしているか、実質的なものを何も検証していません。テストを修正してください
- エラーになった場合 → テスト環境を修正し、正しく失敗するまで再実行します
GREEN — 最小限のコード
通過する最もシンプルなコードを書きます。余分な機能、ついでのリファクタリング、YAGNI に反するオプションオブジェクトは追加しません。
GREEN を確認 — 必須
もう一度実行します。関連するテストがすべて通過することを確認します。新しい警告やエラーを無視しません。
リファクタリング
GREEN の後に限り、名前、重複、ヘルパーを整理します。テストを通過した状態に保ちます。動作を追加しません(新しい動作には、新しい RED が必要です)。
良いテストと悪いテスト(リズムの観点)
| 良い | 悪い | |
|---|---|---|
| 規模 | 動作は1つ。名前に「そして」が含まれる場合は分割 | あれもこれも詰め込んだテスト |
| 名前 | 観察できる動作を説明している | test1 / works |
| 証明 | 正しい理由で RED になるのを確認した | 初回実行で通過した |
| 深さ | 契約を検証する(test-design) | toHaveBeenCalled だけ/カバレッジを稼ぐだけ |
正当化の一覧
| 言い訳 | 実態 |
|---|---|
| "後でテストして確認する" | すぐに成功しても、何も証明できません。バグを検出するところを一度も確認していません。 |
| "実装後のテストでも同じ目的を達成できる" | 実装後は「これは何をするのか?」を確認します。最初にテストする場合は「これは何をすべきか?」を確認します。 |
| "すでに手動でテストした" | その場限りで、記録もなく、再実行もできません。 |
| "テストするには簡単すぎる" | 簡単なコードでも壊れます。対象を絞ったテストなら低コストです。 |
| "X 時間分を削除するのは無駄だ" | サンクコストです。検証されていないコードは負債です。削除してやり直してください。 |
| "参考用に残す/テストしながら流用する" | それは実装後のテストです。削除するなら、完全に削除してください。 |
| "まず調査する必要がある" | 調査してから、その調査用コードは破棄してください。クリーンな状態で TDD を始めてください。 |
| "TDD は速度を落とす" | 本番環境でのデバッグのほうが時間がかかります。現実的な方法はテストファーストです。 |
| "テストしにくい" | 設計上の問題です。インターフェースをシンプルにしてください(test-design § hard-to-test)。 |
| "既存のコードにテストがない" | 変更するのですから、触れる振る舞いについて失敗するテストを追加してください。 |
| "今回だけ/形式より精神が大事" | 形式と精神は同じです。人間の許可なしに例外は認められません。 |
危険信号 — コードを削除してやり直す
- 失敗するテストより先に本番コードを書いている
- 実装後にテストを書いている
- 初回実行でテストが成功する
- RED になった理由を説明できない
- 「時間を節約するため」に
--no-verifyを使う/テスト実行を省略する - テスト前のコードを「参考用」として残している
- 「現実的な近道」/「今回は事情が違うので…」
どれか一つでも該当したら → 本番コードを削除してください。RED からやり直してください。
アンチパターン(簡易版)
- 単体ではなく、モックの振る舞いをテストする
- 本番用の型に、テスト専用のメソッドを追加する
- 周辺の要素を大量にモックする(多くの場合は単なる接着コードです → 統合テストを優先するか、設計を見直してください — test-design §1/§5)
チェックリスト(振る舞いごと)
- 実際のテストをする価値があるか?(test-design ROI)— そうでなければ、接着コードに対して TDD を装わない
- 契約に基づいて RED を記述し、適切な理由で失敗することを確認した
- GREEN は最小限にし、成功を確認した
- REFACTOR 後も成功し、新しい振る舞いを紛れ込ませていない
- モックは外部環境に限り、アサーションは対象を絞って厳密にした
引き継ぎ
移行ゲート — 機能の一部が完了したとき(または tdd を終了する前)に、ユーザーに確認してください(AskUserQuestion を 1 回使用し、自動で次に進まないでください)。
A) Recommended: Proceed → review (then commit-and-push)
B) Review first — run **review** on the code slice (`references/code.md`; upstream = plan tasks / spec), then return to this gate
C) Adjust — back into a tdd RED→GREEN cycle for the issue, then return to this gate
D) Something else (I will type it)
- ケースの品質が不明確 → test-design
- 境界/モックの過剰 → solid
- 機能の形が不明確 → grill → まず write-spec、その後 TDD
- リリースする → review、続けて commit-and-push