LASSIC Media らしくメディア
テスト駆動開発のやり方|手順とデメリット、BDDとの違い
監修・編集責任者:牛尾 昭昌(株式会社LASSIC 執行役員)
この記事の結論
- テスト駆動開発は、テストリストを作り、テストを1つ書いて失敗させ、通してから整える手順を繰り返す開発の進め方です。
- つまずきやすいのは、テストをまとめて先に書く、期待値に実行結果を写す、整理の手順を飛ばす、の3つです。
- BDDは同じ流れを業務の言葉の例に広げたもので、委託時はテストがCIで回り、読める形で納品されるかを見ます。
※ 本記事は2026年10月時点の公式情報(省庁・公的機関、および製品やサービスを提供する事業者が公開している資料)に基づきます。
テスト駆動開発(TDD)は、コードを書く前にテストを書き、そのテストを通すようにコードを直していく開発の進め方です。言葉は広く知られていますが、「テストを全部先に書くこと」「カバレッジを上げること」と受け取られたまま取り入れられ、手間だけが増えてやめてしまう現場もあります。
本記事では、システム開発に携わるエンジニアやPMの方に向けて、提唱者であるKent Beckが公開している手順の説明やISTQBの用語集をもとに、テスト駆動開発の仕組みとやり方を、Pythonの短い例で1周しながら整理します。あわせて、BDD(振る舞い駆動開発)との違い、実務での使いどころ、デメリットやつまずきやすい点、開発を委託するときに確かめたい点も扱います。
目次
テスト駆動開発とは
ソフトウェアテストの資格制度を運営するISTQBの用語集は、テスト駆動開発を、テストケースを作って自動化し、そのテストケースに合格するようにソフトウェアを少しずつ開発していく技法と定義しています。*3 Martin Fowlerは、1990年代の終わりにKent BeckがXP(エクストリーム・プログラミング)の一部として作り上げた技法だと紹介しています。*2
要点は、テストを品質の確認のためだけでなく、次に何を作るかを決める道具として使うことです。これから足したい振る舞いを、まず実行できるテストの形で書き、それが失敗することを確かめてから、通るだけのコードを書きます。コードが先にあってテストを後から足す進め方とは、順番が逆になります。
テストを先に書くと、そのコードを外からどう呼び出すかを先に考えることになります。Fowlerは、テストを先に考えることで、コードのインターフェースと実装を分けて考えやすくなる点を利点に挙げています。 自動テストの一式が開発の副産物として残り、後の変更で既存の振る舞いが壊れていないかをすぐ確かめられるのも利点です。
Red・Green・Refactorの仕組み
Kent Beckは2023年12月に公開した「Canon TDD」で、テスト駆動開発の手順を5つに整理しています。*1 Fowlerは、このうち中心の3つがよく「Red – Green – Refactor」とまとめられると書いています。*2 テストが失敗する状態(Red)から、通る状態(Green)へ進め、最後にコードを整える(Refactor)という意味です。
最初の手順は、コードではなくテストリストです。変えたい振る舞いについて、基本のケース、タイムアウトしたとき、データがまだ無いとき、といった確かめたいケースを書き出します。Beckは、この段階で実装の設計を混ぜないよう注意しています。*1
次に、リストから1つだけ選んで、準備・呼び出し・アサーション(期待する結果の確認)がそろった、実際に動く自動テストにします。テストを書く段階で決まるのは主に呼び出し方の設計です。そのテストを通すようにコードを直すとき、それまでのテストも全部通すことが条件になります。途中で新しいケースに気づいたら、テストリストに書き足します。
テストが通ったら、必要に応じてリファクタリングをします。ここで初めて、内部の実装をどう組むかを決めます。Beckはこの手順を「任意」としていますが、Fowlerは、この3つ目の手順を省くことがテスト駆動開発で最もよく見かける失敗だと書いています。*2 テストリストが空になるまで、2つ目の手順に戻って繰り返します。
Pythonで1周する具体例
請求書の税込金額を計算する関数を例に、1周を追ってみます。ここでは、税率10%で1円未満は切り捨てる、という仕様に決めたとします(端数の扱いは業務の取り決めによります)。テストリストには「1,000円は1,100円になる」「1円未満は切り捨てる」「負の金額はエラーにする」の3つを書きました。テストはPythonの標準ライブラリのunittestで書き、python -m unittest で実行します。このコマンドは python -m unittest discover と同じで、テストのファイルを自動で見つけて実行します。*8
# test_billing.py(1つ目のテスト)
import unittest
from billing import tax_included
class TaxIncludedTest(unittest.TestCase):
def test_adds_ten_percent(self):
self.assertEqual(tax_included(1000), 1100)
# billing.py はまだ return price だけ
$ python -m unittest
AssertionError: 1000 != 1100
FAILED (failures=1)
1つ目のテストは、関数がまだ金額をそのまま返すだけなので失敗しました。これがRedです。失敗を先に見ておくのは、テストが本当に関数の結果を確かめていることを知るためです。次に、関数の中身を price * 110 // 100 に書き換えると、テストは通りました(Green)。
2つ目の「999円は1,098円」のテストは、書いた時点で通りました。整数の割り算の // が端数を切り捨てるためです。書いてすぐ通るテストは仕様の記録にはなりますが、コードを前に進めてはいません。期待値を一度わざと変えて失敗することを確かめておくと、見ている値の取り違えに気づけます。3つ目の負の金額のテストは「ValueError not raised」で失敗したので、入力の確認を足して通しました。
# billing.py(Refactor後)
TAX_RATE_PERCENT = 10
def tax_included(price: int) -> int:
if price < 0:
raise ValueError("price must be >= 0")
return price * (100 + TAX_RATE_PERCENT) // 100
# test_billing.py に足した2つのテスト
def test_truncates_fraction_below_one_yen(self):
self.assertEqual(tax_included(999), 1098)
def test_rejects_negative_price(self):
with self.assertRaises(ValueError):
tax_included(-1)
$ python -m unittest
Ran 3 tests in 0.000s
OK
最後に、式の中に直接書いていた110を、税率の定数から計算する形に整えました。振る舞いは変えていないので、3つのテストが通ったままであることを確かめて1周が終わります。テストリストが空になったので、この変更はここまでです。pytestやJavaのJUnitでも、書き方が違うだけで流れは同じです。
BDD(振る舞い駆動開発)との違い
BDD(Behaviour-Driven Development)は、Dan Northがテスト駆動開発の教え方から生み出した考え方です。2006年に雑誌に載った「Introducing BDD」でNorthは、テスト駆動開発を教える中で、どこから始めるか、何をテストするか、テストに何と名前を付けるかといった同じ疑問に何度も出会ったと書いています。*5 そこで「テスト」の代わりに「振る舞い」という言葉を使い、テストの名前を振る舞いを表す文にすることから始めました。
Northは、業務分析の担当者と一緒に、この考え方を要件の定義にも広げました。受け入れ条件を、前提となる状況(Given)、起きる出来事(When)、確かめる結果(Then)の形のシナリオで書き、それをそのまま実行できるようにする、というものです。*5 ISTQBの用語集もBDDを、顧客にとって期待される振る舞いを届けることにチームで焦点を当て、それをテストの土台にする協働の進め方と定義しています。*4
| 観点 | テスト駆動開発 | BDD |
|---|---|---|
| 主な担い手 | コードを書くエンジニア | 業務の担当者・テスト担当者・エンジニアのチーム |
| 書くもの | プログラムのテストコード | 業務の言葉で書いた具体例(シナリオ) |
| 扱う単位 | 関数やクラスの小さな振る舞い | ユーザーストーリーや機能の受け入れ条件 |
| 代表的な道具 | unittest、pytest、JUnit | Cucumber(Gherkin)、JBehave |
Cucumberの公式ドキュメントは、BDDの日々の活動を、具体例を話し合って合意する(Discovery)、自動化できる形に書く(Formulation)、例ごとに自動テストから始めて実装する(Automation)の3つの実践に分けています。*6 最後の段階はテスト駆動開発そのものなので、両者は対立するものではなく、BDDはテスト駆動開発を外側から包む形になります。具体例を書く言語がGherkinで、日本語のキーワードも用意されています。
# language: ja
機能: 請求書の税込金額
シナリオ: 1円未満の端数は切り捨てる
前提 税抜の請求金額が999円である
もし 請求書を発行する
ならば 税込の請求金額は1098円になる
シナリオ: 負の金額は受け付けない
前提 税抜の請求金額が-1円である
もし 請求書を発行する
ならば 入力エラーになる
「前提」「もし」「ならば」は、それぞれGiven、When、Thenに当たります。Cucumberは各行をステップ定義と呼ぶコードに結び付けて実行し、1つの例のステップは3〜5個を勧めています。*7 業務の担当者が読んで正しいかを判断できる粒度で書くのがこつです。
実務での使いどころ
テスト駆動開発が向いているのは、入力と期待する結果をはっきり書ける処理です。料金や税の計算、入力値の検証、データの変換、状態の遷移といった業務ロジックは、テストリストを作りやすく、効果も見えやすい領域です。
- 業務ロジックの新規開発:計算や判定の規則をテストリストに落とす
- 不具合の修正:再現するテストを先に書き、失敗を確かめてから直す
- 既存コードの改修:変える前に今の振る舞いをテストで押さえる
- APIの設計:呼び出す側のテストから引数と戻り値を決める
一方で、画面の見た目や操作感のように、結果を先に書きにくいものは向きません。作り捨ての試作で、何を作るか自体を探っている段階も同様です。データベースや外部APIに頼る処理では、テストの間だけ代役に置き換えるテストダブルを組み合わせます。種類と使い分けは「テストダブルとは|モック/スタブの違いと使い分け」で扱っています。
テスト駆動開発で書くテストの多くは単体テストです。コンポーネント同士の連携を確かめる結合テストや、画面から通して確かめるE2Eテストとの役割分担、テストの数の比率をどう組むか(テストピラミッド)は別に考えます。入力をランダムに大量に作って性質を確かめるプロパティベーステストも、テストリストの考え方と組み合わせて使えます。
つまずきやすい点とデメリット
Canon TDDは、手順ごとによくある間違いを挙げています。*1 代表的なものは次のとおりです。
- テストリストをすべてテストコードにしてから、1つずつ通そうとする
- カバレッジを上げるためだけに、アサーションの無いテストを書く
- テストを通すために、アサーションを消す
- 実行して出た値を、そのままテストの期待値に写す
- テストを通す作業とリファクタリングを同時にする
- リファクタリングをやりすぎる、早すぎる段階で抽象化する
テストを先にまとめて書くと、最初のテストを通した時点で設計を見直したくなったとき、書いたテストを全部直すことになります。Beckは、この手戻りと、いつまでも何も通らない状態が続くことを理由に挙げています。 実行結果を期待値に写す間違いについては、二重に確かめるというテスト駆動開発の価値を失わせると書いています。*1 期待値は、仕様や手で計算した値から書きます。
デメリットとして押さえておきたいのは、書くコードの量が増えることです。テストのコードも保守の対象になり、実装の細部に寄りかかったテストは、リファクタリングのたびに壊れて負担になります。テストの名前が振る舞いを表していないと、失敗したときに不具合なのか、仕様が変わったのかの判断がつきません。Northは、仕様が変わって正しくなくなったテストは消してよいとしています。*5
効果の大きさは、対象のシステムやチームの習熟度で変わります。導入するかどうかは、一部の機能で試し、手戻りや不具合の件数を以前の開発と比べて決めるのが確実です。
外部に委託するときに確認しておきたい点
開発を委託するときに「テスト駆動開発で進めます」と言われても、その中身は会社やチームによって違います。提案や途中の成果物で、次の点を確かめておきます。
- テストコードが納品物に含まれ、CI(変更のたびに自動でビルドとテストを回す仕組み)で毎回実行されるか
- テストにアサーションがあり、名前から確かめている振る舞いが読めるか
- カバレッジの数値だけを目標にしていないか
- 受け入れ条件を、発注側も読める具体例で合意しているか
- テストの実行時間と、外部サービスに頼るテストの扱い
カバレッジは、テストで実行されたコードの割合を示すだけで、正しさを保証するものではありません。計測の仕方とゲートの置き方は「テストカバレッジ計測とゲート導入を外注する要点」で扱っています。納品後に自社や別の会社が保守する場合は、テストが読めて回せることが、そのまま引き継ぎの資料になります。
まとめ:テスト駆動開発で確かめておきたい3つの点
確かめておきたい点は3つです。第一に、テスト駆動開発は、テストリストを作り、テストを1つ書いて失敗させ、通してから整える手順を、リストが空になるまで繰り返す進め方であること。第二に、テストをまとめて先に書く、実行結果を期待値に写す、リファクタリングを飛ばす、といった間違いを避けること。第三に、BDDは同じ流れを業務の言葉の具体例に広げたもので、委託ではテストがCIで回り、読める形で残るかを確かめることです。
よくある質問
テスト駆動開発とテストファーストは同じですか
テストを先に書く点は同じです。Martin Fowlerは、テストを先に書くことをXPの解説書(第2版)がテストファースト・プログラミングと呼ぶと紹介したうえで、テスト駆動開発ではテストリストを作ることと、リファクタリングの手順を欠かさないことを重く見ています。
テストを先に書くと、開発に時間がかかりませんか
書くコードの量は増えます。その分、変更のたびに既存の振る舞いが壊れていないかを自動で確かめられます。効果は対象やチームで変わるため、一部の機能で試し、手戻りや不具合の件数を比べてから広げるのが確実です。
既存のシステムにも取り入れられますか
取り入れられます。新しく足す機能や不具合の修正から始め、変える箇所の今の振る舞いを先にテストで押さえます。テストを書きにくい構造の部分は、依存をテストダブルに置き換えられるよう少しずつ整えます。
BDDを取り入れるにはCucumberが必要ですか
必須ではありません。Cucumberの公式ドキュメントも、BDDはCucumberを使うことにとどまらないとしています。まず業務の担当者と具体例を話し合って合意することが中心で、道具はその具体例を自動で確かめる手段です。
テスト駆動開発を取り入れた開発のご相談
元請(プライムベンダー)として、テストの自動化とCIの整備を含めたシステム開発から、保守・運用までご提案します。
Remoguとリラシクなら、テストの自動化や品質の改善に加わるITエンジニアも探せます。
Remoguは、リモート前提で全国から即戦力のITプロ人材を調達するサービスです。リラシクは、扱う求人がすべてリモートワークのITエンジニア専門転職エージェントです。どちらもLASSICが運営しています。
出典
- *1 参考:Kent Beck「Canon TDD」(Software Design: Tidy First?、2023年12月11日)(https://newsletter.kentbeck.com/p/canon-tdd)。出典:5つの手順(Test List、Write a Test、Make it Pass、Optionally Refactor、繰り返し)と各手順の Mistake を参照(2026年10月確認)
- *2 参考:Martin Fowler「TestDrivenDevelopment」(bliki、2023年12月11日更新)(https://martinfowler.com/bliki/TestDrivenDevelopment.html)。出典:Kent BeckによるXPでの考案、Red – Green – Refactor、インターフェースと実装の分離、3つ目の手順を省く失敗を参照(解説として補助的に使用)(2026年10月確認)
- *3 参考:ISTQB Glossary「test-driven development」(https://glossary.istqb.org/en_US/term/test-driven-development)。出典:定義(version 2)を参照(2026年10月確認)
- *4 参考:ISTQB Glossary「behavior-driven development」(https://glossary.istqb.org/en_US/term/behavior-driven-development)。出典:定義(version 1)を参照(2026年10月確認)
- *5 参考:Dan North「Introducing BDD」(初出 Better Software 2006年3月号)(https://dannorth.net/blog/introducing-bdd/)。出典:TDDを教える中での疑問、「behaviour」への言い換え、Given/When/Thenのシナリオ、仕様が変わったテストの削除を参照(2026年10月確認)
- *6 参考:Cucumber「Behaviour-Driven Development」(https://cucumber.io/docs/bdd/)。出典:Discovery・Formulation・Automationの3つの実践、BDDはCucumberを使うことにとどまらないとする説明を参照(2026年10月確認)
- *7 参考:Cucumber「Gherkin Reference」「Localisation」(https://cucumber.io/docs/gherkin/reference/)。出典:Given/When/Then、ステップ定義、1つの例に3〜5ステップを勧める説明、日本語のキーワード(https://cucumber.io/docs/gherkin/languages/)を参照(2026年10月確認)
- *8 参考:Python Software Foundation「unittest — Unit testing framework」(https://docs.python.org/3/library/unittest.html)。出典:Test Discovery(python -m unittest は python -m unittest discover と同じ)を参照(2026年10月確認)