---
name: test-driven-development
description: 新機能実装やバグ修正を行う際、実装コードを書く前に必ず使用する。
---

# テスト駆動開発（TDD）

常に使う: 新機能・バグ修正・リファクタリング・振る舞い変更
例外（ユーザーに確認）: 使い捨てプロトタイプ・生成コード・設定ファイル

テストを先に書く -> 実装 -> テスト実行で確認。

## 仕様の受け渡し（必須）

設計書を丸ごと読まない・読ませない。extract.js で必要ブロックのみ:

```bash
# テスト生成用（結合/E2E ありなら フロー も追加）
node .spec-runner/scripts/extract.js "{node_id}" --blocks 定数,公開IF,入出力,テスト仕様

# 実装生成用
node .spec-runner/scripts/extract.js "{node_id}" --blocks 概要,定数,公開IF,入出力,状態,フロー,非機能
```

存在しないブロックはスキップされる。

## サブエージェント連携

- 実装: `@implement-code`
- テスト実行: `@run-tests`

## Step 1: テスト種別を決める

比率: 単体（多数）> 結合（中程度）> E2E（少数）。仕様の `テスト仕様.type` があればそれに従う。迷ったら単体。

| 実装するもの | テスト |
|---|---|
| ロジック・計算 | 単体 |
| DB 操作 | 結合 |
| API エンドポイント | 結合（主要シナリオのみ E2E） |
| 複数サービスをまたぐフロー | 結合 |
| ユーザー向け主要機能 | 単体＋結合（E2E は絞る） |
| バグ修正 | 再現できる最小レベル |

| 種別 | 対象 | 外部依存 | 速度 |
|---|---|---|---|
| 単体 | 関数・クラスの振る舞い（ロジック・エラー処理・バリデーション） | 遅い・副作用ある依存のみモック | ms。CI 毎回 |
| 結合 | モジュール連携、DB・外部 API 境界 | 原則実物（テスト用 DB 等）。動かせないものだけスタブ | 秒。PR ごと |
| E2E | ユーザーシナリオ全体 | モックなし | 分。頻度を落とす |

E2E は維持コスト高 -> 書く前に「単体＋結合で代替できないか」を問う。

## Step 2: テストを書く（TestGen）

仕様の `テスト仕様` を全件、失敗するテストとして実装。委任テンプレート:

```
テスト作成タスク。下記YAML仕様の「テスト仕様」を全件実装する。実装コードはまだ無い（TDD red phase）。

## 規約（必読）
.github/instructions/test-backend.instructions.md（または test-frontend.instructions.md）, .github/instructions/code-common.instructions.md のテスト記述 section

## 仕様 [node: {node_id}]
{extract.js --blocks 定数,公開IF,入出力,テスト仕様 の出力}

## テスト対象
- モジュール: {maps_to の src/ パス}（未作成。望ましい import 形で書く）
- テスト配置先: {maps_to の tests/ パス}

## 制約
- T-XX を関数名に埋め込む。テスト仕様の id と1対1、過不足なし
- 各テストに `# 準備` / `# 実行` / `# 検証` マーカー必須
- モックは外部 I/O のみ（type が結合なら実物依存）
- covers 宣言のあるテストは必ず例外型を検証
- 出力: テストコードのみ
```

要件: 1振る舞い1テスト / テスト名が振る舞いを説明 / 望ましい API の使い方が伝わる書き方。

## Step 3: 実装する（CodeGen）

**1サイクルで実装する T-XX は5個まで**。超えるなら分割し、サイクルごとに結果を報告してから次へ（大タスクの無人一括実装は事故る）。

`@implement-code` に委任。テンプレート:

```
実装タスク。下記YAML仕様が唯一の正。設計書の再確認は不要（確認済み）。

## 規約（必読）
.github/instructions/code-common.instructions.md, .github/instructions/code-backend.instructions.md（または code-frontend.instructions.md）

## 仕様 [node: {node_id}]
{extract.js --blocks 概要,定数,公開IF,入出力,状態,フロー,非機能 の出力}

## 失敗中のテスト(これを通す)
{テストファイルパス}: {失敗中の T-XX 一覧}

## 変更対象(maps_to。これ以外のファイルを変更しない)
{maps_to の src/ パス一覧}

## 制約
- フローの step 順とコードの処理順を一致させる。定数は仕様の値をそのまま使う
- 公開IF があれば Router 配線（エンドポイント登録・ステータス対応）まで実装範囲
- tx で括られた動作は同一トランザクション
- 仕様にない振る舞いを追加しない。矛盾を見つけたら実装せず1行報告で停止
- 出力: 変更コードと報告フォーマットのみ
```

## Step 4: テスト実行で確認

`@run-tests` に委任。確認項目:

- テストが通る。同種テスト全件も通る
- 出力クリーン（エラー・警告なし）
- カバレッジ未カバー行 -> 新規コードが未カバーなら追加テスト
- `scan.js` の drift 警告 0（定数・公開IF・例外型・T-XX が実装とテストに現れる）

落ちたら実装を直す。他のテストが落ちたら直ちに修正。

## Step 5: 整理

重複削除・命名改善・ヘルパ抽出。テストは通ったまま。新しい挙動は追加しない。
-> Step 2 へ戻り次の振る舞いへ。

---

## 参考

### fixture / テストデータ

- テストごとに独立した状態
- 生成はヘルパ関数で一貫性を保つ。ドメインモデルの全フィールドを含める
- 結合用シードデータは `tests/integration/fixtures/`

### モック

モックは分離の手段。テスト対象ではない。

- 実コンポーネントの出力をテストする。モック呼び出し確認だけにアサートしない
- 本番クラスにテスト専用メソッド禁止 -> fixture・テストユーティリティへ
- モック前の自問: 実メソッドの副作用は何か -> テストがそれに依存するか -> 依存するならより低いレベルをモック

設計見直しのサイン: モック準備がテスト本体より長い / モックを外すと成立しない / 必要性を説明できない

### 詰まったとき

| 問題 | 解決 |
|------|------|
| テスト方法が不明 | 望む API とアサーションを先に書く。ユーザーに相談 |
| 種別に迷う | 単体から。書けないなら結合 |
| テストが複雑すぎる | 設計が複雑。インターフェースを簡素化 |
| 何でもモック必須 | 結合が強すぎる。DI を使う or 結合テストで書く |
| セットアップ巨大 | fixture へ抽出。それでも大きいなら設計を簡素化 |
| E2E が遅い | 単体・結合に落とせないか検討 |
