t_wada式 TDD サイクル
t_wadaのTDDプラクティスに忠実に従い、Red→Green→Refactorのサイクルを回す。
基本原則
- •テストが先、実装が後。例外なし
- •動作するきれいなコードがゴール
- •一度に1つのテストだけに集中する
- •テストコードも本番コードと同じ品質を保つ
手順
Phase 0: TODOリスト作成
$ARGUMENTSの内容を分析し、実装に必要なテストケースをTODOリストとして洗い出す。
- •実装したい機能を小さなステップに分解する
- •各ステップをテストケース名(日本語)として書き出す
- •最も簡単で、最も重要なテストケースを最初に選ぶ
- •TODOリストをユーザに提示し、合意を得る
code
TODOリスト例: - [ ] 空文字列を渡すとバリデーションエラーになること - [ ] 有効な値を渡すとオブジェクトが生成されること - [ ] 境界値で正しく動作すること
Phase 1: 🔴 Red(失敗するテストを書く)
- •TODOリストから1つだけテストケースを選ぶ
- •テストファイルを作成/編集する
- •配置: ソースファイルと同じディレクトリにco-locate(
*.test.ts) - •テストケース名は日本語で記述する
- •
describeで正常系・異常系を分類する
- •配置: ソースファイルと同じディレクトリにco-locate(
- •テストを実行し、失敗することを確認する
- •
npm run test:domain、npm run test:server、npm run test:clientのうち適切なものを使用 - •失敗理由が意図通りか確認する(コンパイルエラーではなくアサーション失敗が理想)
- •
- •失敗を確認できたら次のフェーズへ進む
重要: このフェーズではプロダクションコードを書かない。テストだけを書く。
Phase 2: 🟢 Green(最小限の実装で通す)
以下の3つの戦略を段階的に使い分ける:
戦略1: 仮実装(Fake It)
- •テストを通す最も簡単な実装を書く
- •ハードコードした値を返すだけでもOK
- •目的: まず「グリーン」の状態を作る
typescript
// 例: 最初はハードコードで通す
getDisplayName(): string {
return "太郎"
}
戦略2: 三角測量(Triangulate)
- •1つ目のテストが仮実装で通ったら、2つ目のテストケースを追加する
- •2つのテストを同時に通すには、仮実装では不十分になる
- •これにより汎用的な実装へ進化させる
typescript
// 2つのテストケースが存在するので、ハードコードでは通らない
// → 汎用的な実装に書き換える
getDisplayName(): string {
return this.name
}
戦略3: 明白な実装(Obvious Implementation)
- •実装方法が明らかな場合は、直接正しい実装を書く
- •ただし、テストが失敗したら仮実装に戻る
重要: テストを実行し、グリーンになったことを確認する。
Phase 3: 🔵 Refactor(リファクタリング)
テストがグリーンの状態を維持しながら、コードを改善する。
- •プロダクションコードの重複を除去する
- •テストコードの重複を除去する(テストコードもリファクタリング対象)
- •命名を改善する
- •リファクタリング後、テストを実行してグリーンを確認する
- •必要に応じて
npm run lintを実行する
重要: リファクタリング中に新しい機能を追加しない。振る舞いを変えずに構造を改善する。
Phase 4: サイクルを繰り返す
- •TODOリストの完了したテストケースにチェックを入れる
- •次のテストケースを選び、Phase 1に戻る
- •実装中に気づいた新しいテストケースはTODOリストに追加する
- •全てのTODOが完了するまで繰り返す
プロジェクト固有のルール
- •テストフレームワーク: Vitest(globals有効、import不要)
- •テストファイル命名:
*.test.ts/*.test.tsx - •テスト配置: ソースファイルと同じディレクトリにco-locate
- •モック:
vitest-mock-extendedのmockDeepを使用 - •テストデータ:
@faker-js/fakerで生成 - •バリデーション: Zodスキーマの
safeParse()でテスト - •結果型:
@yuukihayashi0510/coreのsuccess/failureパターン - •パラメータ化テスト:
it.each()を活用 - •インポート:
@/*の絶対パスを使用 - •テストケース名: 日本語で記述
テストコマンド
対象に応じて適切なコマンドを使う:
- •
npm run test:domain- ドメイン層 - •
npm run test:server- API/サーバー層 - •
npm run test:client- フロントエンド層 - •
npm run test:common- 共通層
各フェーズの確認ポイント
| フェーズ | 確認すること |
|---|---|
| Red | テストが意図した理由で失敗しているか |
| Green | 全てのテストがパスしているか(新旧含む) |
| Refactor | リファクタリング後も全テストがパスしているか |
やってはいけないこと
- •失敗するテストなしにプロダクションコードを書く
- •一度に複数のテストケースを実装する
- •Redフェーズでプロダクションコードを書く
- •Refactorフェーズで新機能を追加する
- •テストを実行せずに次のフェーズに進む
- •テストがRedのままRefactorに入る