ユーザーがTDDで実装したいときに使うスキル。「TDDで」「テスト駆動で」「tdd」「/tdd」「テスト先に書いて」「Red-Green」など、実装前にテストを書くことを示す表現があれば必ず使う。「テストもちゃんとやって」「ちゃんとテスト書いて」のような表現でも発動する。Red→Greenサイクルを厳守し、Redの確認ステップを飛ばしてはいけない。
TDDとは、実装の前に失敗するテストを書くことを指す。規律の核心は順序にある: Red → Green — 逆は許されない。Redの確認を飛ばすと、「そのテストがバグを本当に検知できるか」の証明が失われてしまう。
テストコードを1行も書く前に、既存のテストファイルを1〜2本読む。確認するのは:
unittest.mock、pytest-mock、MagicMock、AsyncMock の使い方pytest フィクスチャ vs. ヘルパー関数、モジュールレベルの定数test_<動詞>_<条件> パターンassert vs. assert_called_once_with などfrom src.foo import bar なのか from foo import bar なのかtests/ 配下か、ソースの隣かこれらをそのまま踏襲する。プロジェクトのお作法に沿ったテストは読みやすく、保守しやすい。
実装ファイルに手を加える前に、すべてのテストを書く。意識するのは:
test_uses_target_date_for_api_filter は test_date より断然わかりやすい既存の関数のシグネチャを変更する場合は、このステップでその関数を呼んでいる既存テストもすべて更新する。実装を変える前に、テストスイート全体が新しい契約を反映している状態にする。
まだ実装しない。ハードコードされた値を返すスタブすら書かない。
テストを実行する。書いたテストが失敗していることを確認しなければならない。許容されるRed状態:
ImportError / ModuleNotFoundError — モジュールがまだ存在しないTypeError — 引数の数が違う(シグネチャ変更)AssertionError — 実装が新しい期待値を満たしていない実装なしで新しいテストがパスしてしまう場合、そのテストは何もテストしていない。原因を調べて直してから次へ進む。
# プロジェクトのテストランナーに合わせて変える
uv run pytest tests/ -q
# または: pytest, python -m pytest, npm test, go test ./..., など
Redの出力を確認するまで Step 3 に進んではいけない。
失敗しているテストをパスさせる最小限のコードを書く。「最小限」とは:
シグネチャを変更した場合、実装側の呼び出し箇所もすべて更新する(テストは Step 1 で更新済みのはず)。
新しいテストだけでなく、テストスイート全体を実行する。すべてパスしなければならない。
uv run pytest tests/ -q
# 期待: all passed, 0 failed
既存テストが壊れていたらリグレッション。それを直してから完了とする。
ユーザーに伝えること:
シグネチャ変更時に一部の呼び出し元だけ更新する。 collect() が collect(target_date) になるなら、テストファイルも main の呼び出しもすべて同じパスで更新する。そうしないと Step 2 の Red が無関係な失敗で汚れる。
テスト対象をモックする。 collect() をテストするとき、collect 自体をモックしてはいけない。依存している外部(HTTPクライアント、feedparser など)をモックする。
「どうせ失敗するのが明らか」だからと Red を飛ばす。 それでも実行する。Redの出力は「何がなぜ失敗しているか」を正確に教えてくれ、Step 3 の実装の指針になる。
Step 3 で過剰実装する。 単純な if/else でテストが通るなら、その if/else を出荷する。テストが増えてから必要になればリファクタリングする。
pytest tests/ -q # 簡潔な出力
pytest tests/foo.py -v # 特定ファイルを詳細表示
モックは unittest.mock.patch、MagicMock、AsyncMock を既存パターンに合わせて使う。
npm test -- --watch=false
npx vitest run
go test ./...
テストランナーのコマンドをプロジェクトに合わせて変える。Red→Greenの規律は言語を問わず同じ。