テスト駆動開発/振る舞い駆動開発を始めるための基礎知識:いまさら聞けないTDD/BDD超入門(1)(2/3 ページ)
TDDの概要と進め方、目的と効果、歴史、さまざまな手法への展開、課題に加え、BDDの概要と種類、 重視される考え方などを解説する。
ユーザー価値や上位設計とTDDをつなげるさまざまな手法と課題
TDDはシンプルな原則やルールで構成されます。運用では実践者の裁量に依存する部分が多いですし、応用の余地も小さくありません。そのためTDDが普及するに従って、TDDをよりよく活用するための工夫やノウハウが蓄積されていきました。
今回は、その工夫やノウハウの一つとして、ユーザー価値や上位設計とTDDをつなげる手法を紹介します。
インサイドアウトTDDとは
プログラミング手法としてのTDDでは、クラスや関数といったコンポーネント単位の粒度でテストファーストのサイクルを回していくスタイルが一般的です。そのスタイルでは、以下のようなアプローチがしばしば採られることになります(このアプローチは、後述するアウトサイドインTDDと対比して、「インサイドアウトTDD」と呼ばれます)。
- TDDのテストファーストのサイクルで、コンポーネントごとに設計を考えていく
- 各コンポーネントを積み上げながら、インクリメンタルに全体設計を構築していく
このTDDでありがちなインサイドアウトのアプローチについては、Mockオブジェクトの使用の手間が省ける、プログラマー主体の柔軟な設計の作り込みに対応できるといったメリットを持っています。
インサイドアウトTDDの2つの批判
ただ一方で、これに対して主に2つの批判がなされています。1つはアーキテクチャ設計やコンポーネントセットの設計といった、より大きな設計の全体整合を保証しにくくなること、もう1つはユーザー要求やアーキテクチャ設計といった上位のインプットと、TDDのプログラミングが断絶することです。
こうした問題は、設計品質の問題で開発の手戻りコストや保守コストを悪化させる、またユーザーへの価値の実現というテストファーストの当初の目的を欠落させるといった課題を発生させてきました。
アウトサイドインTDDとは
そこでTDDのアプローチとして以下を行う手法が確立されました。
- 最初にアーキテクチャなどの全体構造の設計を行い、TDDの対象となるコンポーネントの振る舞いを明確化してからテストファーストのサイクルを回す
- テストファーストプログラミングのツールとして開発された「モック(Mock)」を未実装コンポーネントの代替として活用する。モックオブジェクトで未実装状態でも全体設計を仮想的にテストで動かせる状態にした上で、TDDでモックオブジェクトを本物のオブジェクトに置き換えていく
このアプローチは包括的な外側の「振る舞い」をテストで記述した後、内側の個々のコンポーネントを実装していくという方向性から、「アウトサイドインTDD」と呼ばれます(プログラミングのドメインに限った場合、人によってはアウトサイドインTDDを「モック派」と呼び、前述のインサイドアウトTDDを「古典派」と呼ぶ場合もあります)。
アウトサイドインTDDが重視するのは、「良いソフトウェアを作るために、TDDでの実装対象はどのような振る舞いをするべきか」という要求を明確化することと、それをテストで記述し、そのテストで開発を駆動させていくことです。この実践で、TDDにおいて全体整合の取れた設計を実現する他、不適切なテストで不適切に開発が駆動される流れを防止します。
アウトサイドインTDDの課題
注意として、アウトサイドインTDDはメリットだけではなく、対応すべき課題を持っています。
例えば、アウトサイドインTDDではモックを多用するため、TDDのテンポを阻害しない軽快さでモックやエクスペクテーションを記述できるモックライブラリや開発環境を必要とします。
また変化に対応でき、品質の高い設計を実現する技量がないと、アウトサイドインは厳格に要求仕様化を行い、厳格に基本設計・詳細設計を行って、詳細仕様の通りにTDDを進めるというウォーターフォール的なアプローチになりがちです。そうなってしまうと、アジャイルやTDDのメリットを目減りさせることになります。
TDDの第2のバイブル
なお2000年代後半に、「JMock」の開発者であるSteve Freeman氏が、変化に対応するためのオブジェクト指向設計のノウハウを基礎にアウトサイドインTDDを展開するアプローチを書籍『Growing Object-Oriented Software Guided by Tests』(邦題『実践テスト駆動開発〜テストに導かれてオブジェクト指向ソフトウェアを育てる』翔泳社刊)にまとめています。
この本は国内のTDDコミュニティで、『Test Driven Development By Example』に続く「TDDの第2のバイブル」と位置付けられています。
テストファーストのダブルループ
またアウトサイドインTDDでカバーできないさらに上位のテストレベルとのつながりを明確化するために、「テストファーストのダブルループ」というアプローチが考案されました(参考『Growing Object-Oriented Software Guided by Tests』)。
これは「End-To-Endテスト」(システムテスト)の自動化環境と、単体テストの自動化環境を構築し、両方でテストファーストを回していくアプローチです。具体的には、以下の手順を採ります。
- End-To-Endテストで失敗するテストを書く。なお未実装のコンポーネントがある場合は、ウォーキングスケルトン(モックなどを使って実行可能にしたアーキテクチャのスケルトン)を構築して最低限のテストだけ実行可能にする
- End-To-Endテストを成功させるように、アウトサイドインTDDでプロダクトコードを実装する
これはアウトサイドインTDDと相性が良いアプローチです。End-To-Endテストのテストファーストでユーザーの要求レベルからアーキテクチャ設計レベルまでのブレークダウンをサポートします。アウトサイドインTDDでアーキテクチャ設計レベルから、コンポーネント設計レベルまで仕様・振る舞いをブレークダウンすることを可能にすることで、ユーザーの要求から実装までをテストファーストで駆動できるようになります。
TDDからの、他のテストファースト手法への展開
TDDの普及は、他のテストファースト手法にも影響を与えています。例えば、TDDにおいて明確にされたテストファーストのメリットや問題対策を他領域に展開しようとする動き、TDDの運用を通じて整備が進んだテスト自動化環境の活用などです。
次ページでは、TDDが影響を与えた開発手法の代表例である、BDDを紹介します。
Copyright © ITmedia, Inc. All Rights Reserved.