👋

「AIに先にテストを全部書かせる」はTDDじゃない。でも、それもアリだよね。

に公開

こんにちは、ログラスの松岡(@little_hand_s)です

3行まとめ

  • 「先にテストをまとめて書かせる」はTDDではない(サイクルと目的が違う)
  • 従来のTDDでは非推奨だったが、AI時代では有効な手法に
  • 違いを理解して使い分けることで、AI時代の開発がより効果的になる

AI時代のTDDと、混乱しやすい実現方法

最近、AI開発の文脈で「TDD(Test-Driven Development:テスト駆動設計)が有効」という話をよく聞くようになりました。

ClaudeCode公式のベストプラクティスでも「TDDはエージェンティックコーディングによってさらに強力になる」と述べられており、TDDの生みの親Kent Beckも「TDDはAIエージェントと働く際のスーパーパワー」と語っています。

実際にClaudeCodeなどのAIエージェントに実装を任せると、必要なテストコードを先にまとめて生成し、それを通すようにプロダクションコードを生成してくれることがあります。これは一見、「テストファースト」でTDDのような感じがしますよね。

しかし、これは厳密にはTDDではありません。
でも、それが悪いというわけでもありません。

この記事では、その違いと使い分け方を解説し、AI時代の開発をより効果的にする方法を紹介します。

TDDとテストの事前一括作成の決定的な違い

まず、用語を整理しておきましょう。

「テストを先に書く」という点では共通していますが、「どのようにテストを書くか」「何のために行うか」 が異なります。

本記事では、以下のように整理します:

  • TDD(Test-Driven Development): Red-Green-Refactorのサイクルで設計を改善する開発手法
  • テストの事前一括作成: 機能のテストをまとめて先に実装すること(※手法として定義されたものではなく、区別のための本記事の呼称)

それぞれ詳しく見ていきましょう。

TDD(Test-Driven Development:テスト駆動開発)とは

TDDは、テストを通じて開発を駆動し、 "動作するきれいなコード(clean code that works)"を目指す 開発手法です。

  • 定義: テストによって開発を駆動する手法
  • 目的: 動作するきれいなコード
  • 手法: Red→Green→Refactorの超短い反復(数分サイクル)
    • Red: 先にテストコードを書いて実行し、失敗させる
    • Green: プロダクションコードを実装し、テストを成功させる
    • Refactor: リファクタリングし、再度テストを成功させる。これにより、設計を改善する。

TDDの特徴は、設計を最初から完璧に決めないこと です。
複雑な問題では最初から正解が見えないため、小さく実装して動かし、得られた知見をもとに設計を改善していきます。この「少しずつ試して学習しながら設計を育てる」アプローチが、不確実性への対処として有効なのです。

補足:似た言葉: SDD(Specification-Driven Development / 仕様駆動開発)について

AI時代の開発手法として、SDD(Specification-Driven Development / 仕様駆動開発) が注目されています。SDDは、コードを書く前に詳細な仕様書(specification documents)を作成し、その仕様からテスト・設計・実装を逆算して進める手法です。

重要な違い:SDDは「テストファースト」の手法ではなく、「仕様ドキュメントファースト」 の手法です。仕様書を「唯一の真実源泉(Single Source of Truth)」として位置づけ、AIに仕様を明確に伝えることを重視します。

TDDとSDDの関係:SDDとTDDは異なるレイヤーの手法であり、組み合わせて使うことができます。SDDでは仕様から受入基準を定義し、その実装フェーズでTDDを使って設計を改善していくアプローチが一般的です。

例えば、Amazon Kiroなどのツールでは、requirements.md(要件定義)→ design.md(技術設計)→ tasks.md(タスク分解)という仕様ドキュメントを作成した後、実装時に「TDD前提で実装を行う」ことが推奨されています。

参考Understanding Spec-Driven-Development - Birgitta Böckeler (martinfowler.com)

テストの事前一括作成とは

機能単位でテストをまとめて先に書く方法です。

  • 定義: 機能単位(など)でプロダクションコードの実装前にテストをまとめて先に書く方法
  • 目的: 仕様の明確化・完了条件の明示
  • 手法: 機能のテストを実装前にまとめて書く
    • 例:割引計算機能なら、正常な割引、0円以下の異常系、上限チェックなどを一度に書く

従来のTDDとの関係:一括作成は「よくある間違い」とされていた

従来のTDDでは、テストを一括で事前に書くアプローチは推奨されていませんでした。

TDDでは、実装前に「Test List」(必要なテストケースのリスト)を作成することがあります。このTest Listについて、TDDの生みの親であるKent Beckは、2023年の記事「Canon TDD」で、使い方の間違いを指摘しています:

"A common mistake is to convert all the items on the Test List into concrete tests, then make them pass one at a time.
(よくある間違いは、Test Listのすべての項目を具体的なテストに変換してから、1つずつパスさせることだ。)

なぜこれが問題なのか:

  1. 手戻りのリスク:

    • 最初のテストをパスさせる過程で設計を変更すると、後続のテストの前提が崩れる可能性があります。
    • 例えば、Test #1をパスさせるために関数のシグネチャを変更したら、Test #2〜#6も全て書き直しになる、といった状況です。
  2. モチベーションの喪失:

    • 6つのテストを書いても、実装を始めるまで何も「Green(テストがパスした状態)」になりません。人間は小さな成功体験を積み重ねることでモチベーションを維持しやすいのですが、一括作成ではそれが得られません。
    • さらに、Test #1をパスさせようとしたときに設計変更が必要になると、Test #2〜#6も修正が必要になり、「まだ緑を1つも見ていないのに手戻りが発生する」という二重の苦痛が生じます。

正しいアプローチ:

Kent Beckが推奨するのは、Test Listを「計画」として扱い、そこから1つずつ具体的なテストに変換してパスさせてから次に進む方法です。実装中に新しいテストケースを発見したら、Test Listに追加します。つまり、Test Listは固定された「実装仕様」ではなく、動的に更新される「計画」なのです。


AI時代での変化:一括が有効な場面も出てきた

しかし、AI時代においては状況が変わり、テストの事前一括作成に有利な点が見えてきました。

AIコード生成による変化:

  • テストが「AIへの明確な指示」として機能し、生成品質が向上する
  • 仕様が明確な場合、AIが網羅的なテストを一気に生成できる

従来は「手戻りのリスク」や「モチベーションの喪失」が問題でしたが、AIが実装を高速にサポートすることで、これらの問題は大幅に解消されます。仕様が明確で設計の不確実性が低い場合には、テストの事前一括作成が有効な選択肢となります。

ClaudeCode公式のベストプラクティスでも、以下のように述べられています:

Claude performs best when it has a clear target to iterate against—a visual mock, a test case, or another kind of output. By providing expected outputs like tests, Claude can make changes, evaluate results, and incrementally improve until it succeeds.

(Claudeは、ビジュアルモック、テストケース、その他の出力など、明確な目標に対して反復する際に最高のパフォーマンスを発揮します。テストのような期待される出力を提供することで、Claudeは変更を加え、結果を評価し、成功するまで段階的に改善できます。)

つまり、明確なテストがあることで、AIが段階的に改善しながら正解に辿り着けるのです。仕様が明確な場合、テストの事前一括作成はAIの強みを最大限に活かせます。

TDD:AI時代でもやっぱり大事

Kent Beckは、TDDの目標を "clean code that works"(動くきれいなコード) と定義しています。ここで重要なのは、「動く」と「きれい」を2つの独立した問題として扱い、まず動かし(Green)、次にきれいにする(Refactor)という短いサイクルを繰り返すアプローチです。設計を最初に完璧に決めるのではなく、このサイクルを通じて段階的に改善していきます。

AI時代になり、コード生成は圧倒的に楽になりました。しかし、複雑な問題における不確実性という本質的な課題は変わっていません。

TDD第一人者の和田卓人(@t_wada)氏は、AI時代のTDDについて以下のように述べています(※1):

「テスト駆動開発で」という指示がAIの暴走を防ぐガードレールとして有効になります

AIは高速にコードを生成できますが、「目的のコードを得ようといろいろ動かして、よくコードを壊します」。構文的には正しくても論理的に誤ったコードを生成したり、ビジネス文脈を欠いた「もっともらしいが誤った解決策」を提示したりするのです。

複雑な問題は最初から正解が見えず、実装しながら得られる情報(「この設計では拡張しづらい」「この処理順では問題が起きる」など)をもとに設計を改善する必要があります。
だからこそ、TDDの特徴である「設計を最初から完璧に決めず、少しずつ試して学習しながら設計を育てる」アプローチが、この不確実性への対処として有効なのです。


AI時代における使い分け:実践的な判断基準

TDDとテストの事前一括作成、どう使い分ければ良いのでしょうか?

ポイントは、 問題の不確実性と複雑度 です。以下、具体的な判断基準を見ていきましょう。

1. TDDを使う場面

複雑度が高く、実装しながら設計を育てる必要がある場合に適しています。実装してみて初めて得られる情報(「この設計では拡張しづらい」「この処理順では問題が起きる」など)が重要な判断材料になるケースです。

具体例:

たとえば、ECサイトの注文処理システムを実装する場合:

  • 在庫管理、決済、配送状況、キャンセル処理など、複数の要素が相互作用
  • 「在庫が足りない場合の決済はどうする?」「キャンセル時の在庫復元タイミングは?」など、実装してみないと気づかない仕様が次々出てくる
  • ドメイン知識を深めながら、クラス設計やモジュール分割を少しずつ改善していく必要がある

このように、要件が抽象的で、実装しながら問題を発見し、設計を育てていくケースに適しています。

2. テストの事前一括作成を使う場面

要件が明確で、事前に動作を定義できる場合に適しています。

  • 受入基準や期待する動作が明確
  • 仕様が明確で、設計もシンプル
  • AIで受入テストや仕様テストを自動生成したい

具体例:

  • メールアドレス形式のバリデーション(@を含む、ドメイン部分があるなど)
  • 日付フォーマット変換(YYYY/MM/DD → YYYY-MM-DD)
  • 年齢から成人判定(20歳以上)

これらは「入力」と「期待する出力」が明確で、設計の不確実性が低い例です。

3. 実践:組み合わせて使う

この2つは組み合わせて使うことも可能です。受入基準や受入テストはテストの事前一括作成、実装詳細はTDDという組み合わせはとても実践的です。

たとえば:

  1. 受入テストはテストの事前一括作成
  2. 実装開始時には詳細に詰めきれない仕様、技術設計はTDDの中で決めていく

このように、レイヤーごとに不確実性や複雑度に応じて柔軟に選択し、組み合わせることができます。

まとめ

TDDとテストの事前一括作成は、サイクルと目的が異なる別ものです。

従来のTDDでは、テストを一括で事前に書くアプローチは推奨されていませんでしたが、AI時代では状況が変わり、有効な選択肢になりました。

仕様が明確な場合はテストの事前一括作成が効果的に機能し、複雑で不確実性が高い場合はTDDで設計を段階的に改善するアプローチが有効です。この違いを理解して使い分け、組み合わせることで、AI時代の開発がより効果的になります。

書籍の紹介

本記事ではTDDによる設計改善について解説しましたが、「どんな設計を目指すのか」 についてより体系的に学びたい方向けに、筆者はドメイン駆動設計(DDD)に関する書籍も出版しています。

TDDで少しずつ改善していく設計の「理想形」を理解することで、リファクタリングの方向性がより明確になります。

①基礎的な概念や考え方を学びたい方は

https://little-hands.booth.pm/items/1835632

初めてDDDを学ぶ方、もしくは実際に着手して難しさにぶつかっている方向けの書籍です。

特に第4章「設計の基本原則」では、TDDで目指すべき「高凝集・低結合」な設計を具体的なコード例で解説しています。

②実際のコードを見ながら実践したい方は

https://little-hands.booth.pm/items/3363104

実践にあたって頻出の疑問に対して、トピックごとに詳しく解説した書籍です。

特に第7章「テスト」では、DDDにおけるテスト方針とレイヤーごとの具体的なテストコードを解説しており、TDDで書いたテストをどう整理するかの参考にしてもらえると思います。

また、筆者は X(旧Twitter)でアジャイル・DDD・AI駆動開発に関する情報を発信しています。よろしければフォローいただけると嬉しいです。

https://x.com/little_hand_s

参考資料

株式会社ログラス テックブログ

Discussion