tdd-workflow について
機能開発やバグ修正をテスト駆動で進めるためのスキルです。RED、GREEN、REFACTOR、コミットの段階に分け、変更ごとのテスト実行を定めています。
主な機能
- 01RED-GREEN-REFACTOR サイクルの実施
- 02失敗するテストを一度に一つ作成
- 03テストを通す最小限の実装
- 04変更のたびにテストを実行
- 05サイクル完了後のコミット
活用シーン
- 01新機能をテスト優先で実装
- 02バグ修正前に回帰テストを作成
- 03リファクタリング前に特性テストを追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ hieutrtr/ ai1-skills --skill tdd-workflowインストール後、Claude Code で/tdd-workflowを入力して読み込まれたか確認します。
詳細
TDD ワークフロー
使用するタイミング
次の場合に、このスキルを有効にします。
- ユーザーが TDD、テストファースト、またはレッド・グリーン・リファクタリングを明示的に求めている
- テストファーストの価値がある新しい関数、メソッド、エンドポイント、またはコンポーネントを実装する
- 回帰テストを先に書くべきバグを修正する
- ユーザーが「先にテストを書いて」「これを TDD で」「レッド・グリーン・リファクタリング」と言っている
次の場合は、このスキルを使用しないでください。
- 設定ファイル、環境設定、または静的コンテンツ
- 1 行の修正や些細な変更
- 探索的なプロトタイピングや概念実証コード
- 単独で有意義なテストができないコード
- テストパターンの詳細(テストの書き方は
pytest-patternsまたはreact-testing-patternsを使用)
手順
TDD サイクル
┌─────────────────────────────────────────────────────┐
│ │
│ ┌─────┐ ┌───────┐ ┌──────────┐ │
│ │ RED │ ──→ │ GREEN │ ──→ │ REFACTOR │ ──→ ... │
│ └─────┘ └───────┘ └──────────┘ │
│ │
│ Write ONE Write MINIMUM Clean up code │
│ failing code to make while ALL tests │
│ test it pass stay GREEN │
│ │
└─────────────────────────────────────────────────────┘
フェーズ 1:RED — 失敗するテストを書く
- 期待される動作を説明するテストをちょうど 1 つ書きます
- テストは具体的である必要があります。複数ではなく、1 つの動作をテストします
- テストスイートを実行し、新しいテストが失敗することを確認します
- エラーメッセージから、何が不足しているかが明確にわかるようにします
バックエンド(pytest):
pytest tests/unit/test_user_service.py::test_create_user_returns_user -x
# Expected: FAILED (function/class does not exist yet)
フロントエンド(Vitest):
npx vitest run src/hooks/useAuth.test.ts --reporter=verbose
# Expected: FAILED (hook/component does not exist yet)
RED フェーズのルール:
- 要件を表現する最もシンプルなテストを書きます
- 正しい理由(実装がないこと)でテストが失敗するようにします(構文エラーではありません)
- 一度に複数の失敗するテストを書かないでください
- コードがまだ存在していなくても、コードを配置する場所からインポートします
フェーズ 2:GREEN — テストを通す
- 失敗しているテストを通すために必要な最小限のコードを書きます
- 追加の機能、エラー処理、またはエッジケースを加えないでください
- 値をハードコードしたり、シンプルな実装を使ったりしてもかまいません
- テストスイートを実行し、新しいテストだけでなく、すべてのテストが通ることを確認します
# Backend
pytest tests/unit/test_user_service.py -x
# Frontend
npx vitest run src/hooks/useAuth.test.ts
GREEN フェーズのルール:
- 最小限のコードとは、本当に最小限のコードです。定数でテストを満たせるなら、定数を使います
- テストで求められていないコードを追加しないでください
- このフェーズではリファクタリングしないでください
- このフェーズではテストを追加で書かないでください
- テストが通ったら、REFACTOR に進みます
フェーズ 3:REFACTOR — 整理する
- すべてのテストが通った状態を保ちながら、コードの品質を向上させます
- 重複を取り除きます(DRY)
- 命名と可読性を改善します
- 必要に応じて関数やクラスを切り出します
- 変更するたびにテストを実行し、必ず通り続けることを確認します
# After each refactoring change
pytest tests/ -x # Must pass
npx vitest run # Must pass
REFACTOR フェーズのルール:
- すべての変更でテストが通り続けるようにします
- プロダクションコードとテストコードの両方をリファクタリングします
- 新しい機能を追加しないでください(その場合は新たな RED フェーズが必要です)
- テストを壊した場合は、直ちにリファクタリングを取り消します
フェーズ 4:コミット
REFACTOR フェーズが正常に完了したら:
- すべての変更(テストと実装)をステージングします
- 内容がわかるメッセージを付けてコミットします
- 次の動作に向けてフェーズ 1(RED)に戻ります
TDD の厳格なルール
このスキルが有効な場合、次のルールは必ず守ってください。
- 失敗するテストを先に書かずに、プロダクションコードを書かないでください
- 一度に複数の失敗するテストを書かないでください
- テストで求められていない機能を追加しないでください
- 変更のたびに必ずテストを実行してください
- GREEN-REFACTOR サイクルが正常に完了するたびに、必ずコミットしてください
- RED-GREEN-REFACTOR サイクルは必ず短く保ってください(数時間ではなく、数分)
バックエンドの TDD フロー(pytest)
1. Write test: tests/unit/test_user_service.py::test_create_user_returns_user
2. Run: pytest tests/unit/test_user_service.py::test_create_user_returns_user -x
3. See: FAILED - ImportError or AssertionError
4. Implement: app/services/user_service.py (minimum code)
5. Run: pytest tests/unit/test_user_service.py -x
6. See: PASSED
7. Refactor: Clean up, run tests again
8. Commit: "Add UserService.create_user"
9. Next test: test_create_user_rejects_duplicate_email
フロントエンドの TDD フロー(Testing Library)
1. Write test: src/components/UserCard.test.tsx::renders user name
2. Run: npx vitest run src/components/UserCard.test.tsx
3. See: FAILED - module not found
4. Implement: src/components/UserCard.tsx (minimum code)
5. Run: npx vitest run src/components/UserCard.test.tsx
6. See: PASSED
7. Refactor: Clean up, run tests again
8. Commit: "Add UserCard component"
9. Next test: calls onEdit when button clicked
バグ修正の TDD フロー
バグを修正するときは、必ずバグを再現する失敗テストから始めます。
1. Reproduce: Understand the bug and its trigger condition
2. Write test: Test that exercises the exact scenario that causes the bug
3. Run: Confirm FAILED (the test reproduces the bug)
4. Fix: Implement the minimum fix
5. Run: Confirm PASSED (bug is fixed)
6. Refactor: Clean up if needed
7. Commit: "Fix: [describe the bug]"
これにより、テストがバグを検出するため、バグが再発しないことが保証されます。
例
TDD:UserService.create_user(3 サイクル)
サイクル 1 — RED: create_user がユーザーを返すことをテストします
async def test_create_user_returns_user(db_session):
service = UserService(db_session)
user = await service.create_user(UserCreate(email="[email protected]", password="12345678", display_name="A"))
assert user.email == "[email protected]"
assert user.id is not None
GREEN: 基本的なロジックで UserService.create_user を実装します。
REFACTOR: パスワードのハッシュ化を切り出します。コミットします。
サイクル 2 — RED: メールアドレスが重複している場合にエラーが発生することをテストします
async def test_create_user_rejects_duplicate_email(db_session):
service = UserService(db_session)
await service.create_user(UserCreate(email="[email protected]", password="12345678", display_name="A"))
with pytest.raises(ConflictError):
await service.create_user(UserCreate(email="[email protected]", password="87654321", display_name="B"))
GREEN: 挿入前に重複をチェックします。 REFACTOR: 整理します。コミットします。
サイクル 3 — RED: パスワードがハッシュ化されることをテストします
async def test_create_user_hashes_password(db_session):
service = UserService(db_session)
user = await service.create_user(UserCreate(email="[email protected]", password="12345678", display_name="A"))
assert user.hashed_password != "12345678"
assert verify_password("12345678", user.hashed_password)
GREEN: サイクル 1 のリファクタリングですでに通っている場合、このテストは RED ではなく、動作確認です。代わりに、新しい動作をテストしてください。
エッジケース
-
TDDをスキップする場合: 設定ファイル(
.env、tsconfig.json)、静的コンテンツ、自動生成されたコード(Alembicマイグレーション)、一度限りのスクリプト、探索的なプロトタイピング。 -
外部依存関係を伴うTDD: 境界でモック化します。外部APIを呼び出すサービスをテストする場合は、HTTPライブラリではなくAPIクライアントをモック化します。モックではなく、サービスの動作をテストします。
-
大規模な機能: 機能を小さくテスト可能な動作に分割します。各動作に、それぞれ独自のRED-GREEN-REFACTORサイクルを適用します。すべてのサイクルを合わせて、機能全体を実装します。
-
テストのない既存コードのリファクタリング: まず既存の動作をテストするテスト(特性テスト)を書きます。次に、そのテストを安全網としてリファクタリングします。これは厳密なTDDではありませんが、テストファーストの考え方を活用する有効な方法です。
-
パターンスキルとの併用: このスキルでは、テストとコードをいつ書くかというWORKFLOWを定義します。テストをどのように構成するか、どのアサーションを使用するかというPATTERNSには、
pytest-patternsまたはreact-testing-patternsを使用します。