BDD初心者が持ちがちな3大疑問点を提示して、さまざまな角度からそれを明らかにしつつ、振る舞いを表現する2つのテクニックを紹介する。
前回の「TDD/BDDの思想とテスティングフレームワークの関係を整理しよう」では、TDD/BDDについて、その思想と、それをサポートするテスティングフレームワークに分けて解説しました。その中で、TDD/BDDについては実際の熟練者の言葉を借り、テスティングフレームワークについては概要を触れて、その系譜をたどりました。
BDDはその名前に「Behavior」とありますが、「振る舞いとしてのテストコードを書く」とはどういうことなのでしょうか? 難しく考え過ぎる必要はありませんが、「それは振る舞いを書いていないよ」と指摘をする熟練者が何を考えているかを理解することはBDDを習熟していく中で重要な意味を持ってきます。
本記事では「振る舞い」という言葉がどのような意味で使われているのか、という視座でTDD/BDDを解説し、次の3つを明らかにします。
BDDは「テスト」という言葉の代わりに「振る舞い」という言葉によって、開発者に少しでも分かりやすく、そして効果的な設計/実装の普及を狙ってきました。そして、BDDを意識している多くのテスティングフレームワークが生まれているという実績からも「ある程度、認められた手法である」といっていいでしょう。
BDDがそうであるように「ソフトウェアの振る舞いを記述するべきだ」という説明は数多くなされています。振る舞いとは一体何なのでしょうか。そして、どのようなTDD/BDDを実践することが「振る舞いを記述している」といえるのでしょうか?
実際に「ソフトウェアの振る舞いとは何なのでしょうか?」と説明を求められると、困る人もいると思います。確かにBDDフレームワークは、そのAPIによるテンプレートによって「振る舞いを書きやすく」しているかもしれません。ですが、振る舞いが何かを考慮しないのは「フレームワークを使うこと」が目的になってしまう可能性があります。
ここで、実際にBDDやテストコードを推進してきた人たちが、振る舞いとは何かをどのように説明しているかを見てみましょう。
Dan North氏は振る舞いが何であるかについてはあまり語っていませんが、BDDを発展させていく中で「アジャイルにおける『要求分析』と非常に近しい」という考えに到達します。自身のブログ(日本語訳)で、このように記述しています。
ストーリーの振る舞いはシンプルにいえば、ストーリーの「受入基準(acceptance criteria)」です。つまり、もしシステムが全ての受入基準を満たしていれば、システムは正しく振る舞っていることになりますし、そうでなければ、システムが正しく振る舞っていないことになります。そこで私たちはストーリーの受入基準を捉えるためのテンプレートを作りました。
このテンプレートが「Given/When/Then」のスタートになりました。
『レガシーコード改善ガイド』(Working Effectivity with Legacy Code)という書籍があります。この書籍の中で著者のMicheal.C.Feathers氏は次のように言っています。
ソフトウェアで最も大切なのは「振る舞い」であり、振る舞いこそがユーザーの求めるものである。期待される振る舞いを私たちが追加すればユーザーは喜ぶが、ユーザーの求める振る舞いを変更、あるいは削除してしまえば、バグの作り込みとなり、私たちへの信頼は失われてしまう。
(中略)
これは振る舞いの変更でしょうか、追加でしょうか、それとも両方でしょうか。私たちプログラマーには、この問題を明確に区別する有効な方法があります。それは(HTMLなども含めた)コードを変更する必要があるなら、振る舞いの変更とみなす方法です。新しいコードを追加してそれを呼び出すだけなら、大抵は振る舞いの追加とみなします。
(中略)
このメソッド追加は、新しい振る舞いの追加でしょうか、それとも変更でしょうか。答えはどちらもノーです。メソッドを追加するだけで、どこからも呼び出されなければ、振る舞いは変化しないからです。
つまり振る舞いとは、「ユーザーの操作によって“実行”されるソフトウェアの“処理”であり“機能”である。実行されないものは振る舞いとはいわない」ととらえることができます。
『実践テスト駆動開発』(Growing Object-Oriented Software Guided by Tests)という書籍があります。書籍の頭文字から「GOOS」と略されることが多いです。これは「AcceptanceTDD」(受け入れテスト駆動開発)やアウトサイドインなTDD、モックを使ってオブジェクト指向なソフトウェアの設計、テストをするある種の包括的なガイドとなっています。
この書籍では次のように言っています。
システムの振る舞いは、オブジェクトの組み合わせから現れる性質なのだ。『オブジェクトの組み合わせ』とは、すなわち『どのオブジェクトを、どうつなげるか』ということだ。
(中略)
振る舞いのテストを行え、メソッドをテストするのではない
「TDD/BDDにおける振る舞いとは何か」については、あまりハッキリしていないように見えますが、共通して言えそうなのは「対象における何らかのイベントにひも付く外部から見える変化のこと」です。「外部から見える変化」が「関数に対する入力/出力であるのか」「オブジェクトのメッセージングなのか」「画面操作/表示なのか」「時間経過による変化なのか」は対象の違いによるのでしょう。
Martin Fowler氏は、その著書『リファクタリング』(Refactoring)の中でリファクタリングの定義を次のようにしています。
外部から見たときの振る舞いを保ちつつ、理解や修正が簡単になるように、ソフトウェアの内部構造を変化させること。
この定義から逆説的に言えば「リファクタリングをしやすくするためのテストが振る舞いを書いている」と捉えることができます。
TDDやBDDにおいて「振る舞い」の反対は何であるかというと、筆者は「構造」や「仕組み」という言葉を使うことが多いです。先の引用で挙げたリファクタリングでいう「内部構造」も、その一例でしょう。
その一方で書籍やWeb上での表現では、振る舞いに対する対比表現は少なく、実際のコードの説明になったときには、「振る舞い」が「仕様」になり、「振る舞い」の反対語が「実装」に置き換わっていることが多いように見受けられます。
そのように書いてあるものが明示的に「振る舞いとは仕様のことである」とは説明しておらず、突然「仕様」と書いていたり、「仕様を振る舞いとして書く」と表現するにとどめています。これは「仕様と振る舞いが等価ではない可能性」や「振る舞いが一般的用語である可能性」がありますが、振る舞いという用語を説明するのに苦しむ方がいるので、「振る舞いは一般的用語である」とはいいにくいです。
また、この表現はBDDの思想と実際のコードが分断されてしまい、十分に説明できないものを“何となく”使ってしまう可能性があります。
もう少し視野を広くすると「テストはWhat」「プロダクトはHow」と分別していることもあります(これに加えて「ドキュメントにはWhy」とされていることもあります)。これは「テストにはアプリケーションドメイン、プロダクトにはソリューションドメインを書こう」ともいえそうですが、もちろんプロダクトにもアプリケーションドメインを埋め込むので、あまり正確な言い換えではないでしょう。
まとめると、次のような対比表現があると思っていいでしょう。
振る舞いをある程度抽象的に扱う場合、一般的な用語として扱うと、ほぼ同じような意味の「対象における何らかのイベントにひも付く外部から見える変化」といえそうです。
一方でコードレベルで良いTDD/BDDを実践するには「どの立場で振る舞いを捉えているか」をある程度考える必要があります。
また、振る舞いの反対語としては「構造」「内部構造」「仕組み」といった表現があり、振る舞いという言葉を使わない場合、「仕様と構造」「WhatとHow」と対比することもあります。
Copyright © ITmedia, Inc. All Rights Reserved.