TDDとは?——「テストを先に書く」開発手法
TDD(Test-Driven Development:テスト駆動開発)とは、コードを書く前にテストを書く開発手法です。
一般的な開発では「設計 → 実装 → テスト」という順番で進めますが、TDDではこの順番を逆転させます。先にテストを書き、そのテストを通すためにコードを実装するのです。
「テストを先に書くなんて面倒では?」と思うかもしれません。しかし実際には、TDDを実践することでバグが早期に見つかり、結果として開発全体のスピードが上がるケースが多いのです。
この記事では、TDDの基本サイクルからPythonでの実践方法、AI時代に重要性が増す理由まで、初心者向けにステップバイステップで解説します。
TDDの基本サイクル——Red・Green・Refactor
TDDは、3つのステップを繰り返すシンプルなサイクルで成り立っています。信号機の色になぞらえて「Red・Green・Refactor」と呼ばれます。
ステップ1:Red(赤)——失敗するテストを書く
最初に、まだ実装していない機能のテストを書きます。当然、対応するコードが存在しないのでテストは失敗します。この「失敗している状態」が Red です。
ここでのポイントは、「この機能はどう振る舞うべきか」を具体的に考えることです。テストを書く行為そのものが、仕様を整理するプロセスになります。
ステップ2:Green(緑)——テストを通す最小限のコードを書く
次に、テストを通すための必要最小限のコードを書きます。完璧なコードを目指す必要はありません。まずはテストが通る(Green になる)ことだけを目標にします。
ステップ3:Refactor(リファクタリング)——コードをきれいにする
テストが通ったら、外部の振る舞いを変えずにコードの内部構造を改善します。重複の排除、変数名の見直し、処理の整理などを行います。テストがあるおかげで、リファクタリングしても壊れていないことをすぐに確認できます。
この3ステップを小さく素早く繰り返すのが、TDDの基本です。
Pythonで実践するTDD——pytestを使ったハンズオン
ここからは、Pythonのテストフレームワーク「pytest」を使って、TDDを実際に体験してみましょう。
準備:pytestのインストール
pip install pytest
お題:割引計算の関数を作る
「商品価格と割引率を受け取り、割引後の価格を返す関数」をTDDで開発します。
Red——失敗するテストを書く
まず、テストファイル test_discount.py を作成します。
# test_discount.py
from discount import calculate_discount
def test_10percent_discount():
"""1000円の商品に10%割引を適用すると900円になる"""
assert calculate_discount(1000, 10) == 900
def test_no_discount():
"""割引率0%なら元の価格のまま"""
assert calculate_discount(500, 0) == 500
この時点では discount.py が存在しないので、テストを実行するとエラーになります。
pytest test_discount.py
# → FAILED(Red)
これが Red の状態です。テストが「何を作るべきか」を明確に定義してくれています。
Green——テストを通す最小限のコードを書く
discount.py を作成し、テストを通す最小限の実装を書きます。
# discount.py
def calculate_discount(price, discount_percent):
return price * (1 - discount_percent / 100)
テストを実行します。
pytest test_discount.py
# → PASSED(Green)
テストが通りました。Green の状態です。
Refactor——コードを改善する
動作は変えずに、コードの品質を上げます。たとえば、不正な入力に対するバリデーションを追加し、テストも追加します。
# discount.py(リファクタリング後)
def calculate_discount(price: float, discount_percent: float) -> float:
"""割引後の価格を計算する"""
if price < 0:
raise ValueError("価格は0以上で指定してください")
if not (0 <= discount_percent <= 100):
raise ValueError("割引率は0〜100の範囲で指定してください")
return price * (1 - discount_percent / 100)
# test_discount.py(テスト追加)
import pytest
from discount import calculate_discount
def test_10percent_discount():
assert calculate_discount(1000, 10) == 900
def test_no_discount():
assert calculate_discount(500, 0) == 500
def test_negative_price_raises_error():
with pytest.raises(ValueError):
calculate_discount(-100, 10)
def test_over_100_percent_raises_error():
with pytest.raises(ValueError):
calculate_discount(1000, 150)
pytest test_discount.py
# → 4 passed(Green を維持)
リファクタリング後もテストが全て通ることを確認できました。これが Red → Green → Refactor の1サイクルです。
TDDのメリットとデメリット
TDDの導入を検討する上で、メリットとデメリットの両方を理解しておきましょう。
メリット
- バグの早期発見:テストを先に書くため、実装直後にバグに気づけます。後工程で見つかるバグほど修正コストが高くなるため、大きなコスト削減につながります。
- 仕様が明確になる:テストコードが「この機能はこう動くべき」という仕様書の役割を果たします。チーム内の認識のズレも減ります。
- 安心してリファクタリングできる:テストが常に存在するため、コードを改善しても壊れていないことをすぐに確認できます。
- 設計が自然に良くなる:テストしやすいコードを書こうとすると、自然と疎結合で責務の明確な設計になります。
デメリット
- 初期の学習コストがかかる:テストの書き方やTDDの考え方に慣れるまで時間が必要です。
- テストコードの保守が必要:機能の仕様が変わればテストコードも修正する必要があります。
- GUIやUIのテストには不向き:画面の見た目や操作感に関するテストはTDDだけではカバーしにくい領域です。
- 短期的には開発速度が落ちることがある:テストを書く工数が加わるため、慣れないうちは時間がかかります。
とはいえ、中長期で見ればTDDが開発効率を高めることは多くの現場で実証されています。特に、仕様変更が多いプロジェクトやチーム開発では効果が大きいです。
AI時代にTDDが重要になる理由
GitHub CopilotやClaude、ChatGPTなどのAIがコードを生成する時代になり、TDDの価値はむしろ高まっています。その理由を整理します。
テストが「AIへのゴール定義」になる
AIにコードを書かせるとき、テストコードを渡すと精度の高い実装が返ってくることをご存知でしょうか。テストは「この関数はこう動くべき」という明確な仕様です。自然言語の指示よりもはるかに曖昧さがなく、AIにとって最適なゴール定義になります。
たとえば、先ほどの test_discount.py をAIに渡して「このテストが通るコードを書いて」と指示すれば、AIは正確に calculate_discount 関数を生成できます。
AIが書いたコードの品質を担保できる
AIが生成したコードは、一見正しそうでもエッジケースで誤動作することがあります。テストがあれば、AIが生成したコードをすぐに検証できます。テストはAIの出力に対する品質チェックの仕組みとして機能するのです。
人間の役割が「何を作るか考えること」にシフトする
AIがコードを書いてくれるなら、人間に求められるのは「どんな機能が必要か」「どう振る舞うべきか」を考える力です。TDDのテストを書くプロセスは、まさにこの「何を作るべきかを定義する」思考トレーニングそのものです。
TDDを始めるときの3つのコツ
最後に、TDDをスムーズに始めるためのコツを紹介します。
小さく始める
最初から大きな機能をTDDで書こうとすると挫折しがちです。まずはユーティリティ関数やデータ変換処理など、小さな関数から始めましょう。1つのテストケースを書いて通す、この繰り返しに慣れることが大切です。
完璧を目指さない
「テストのカバレッジを100%にしなければ」と考える必要はありません。ビジネスロジックの核心部分からテストを書き始め、徐々に範囲を広げていくのが現実的です。
AIを積極的に活用する
テストコードの雛形をAIに生成してもらい、自分で修正・追加するやり方は、TDD入門の近道です。「この関数のテストケースを考えて」とAIに聞けば、自分では思いつかなかったエッジケースを提案してくれることもあります。
まとめ
TDD(テスト駆動開発)は、テストを先に書いてからコードを実装する開発手法です。
- Red → Green → Refactor の3ステップを小さく繰り返す
- pytestを使えばPythonで手軽にTDDを始められる
- バグの早期発見、仕様の明確化、安全なリファクタリングがメリット
- AI時代には、テストが「AIへの明確なゴール定義」として機能する
- 小さな関数から始めて、少しずつ範囲を広げるのがコツ
AI時代の開発では、コードを書く力よりも「何を作るべきかを定義する力」が重要になっています。TDDは、その力を鍛えるための実践的なフレームワークです。
TDDやAI活用の開発手法を組織に導入したいとお考えの方は、Valuupのセミナーで実践的なノウハウをお伝えしています。まずはお気軽にご参加ください。
