« USB 3.0 ではコネクタ形状が変わる | トップページ | [NUnit 2.5] TestCaseAttribute の使いかた »

2009年6月 9日 (火)

[プログラム設計事始] メソッドの外部設計とテストファースト(2) ~ なんでもユニットテストで記述できるか?

前回は、 メソッドの外部設計をコード ( ユニットテスト ) で表現できるということを説明しました。
そして、 メソッドの外部設計を厳密に定義できるかぎりにおいては、 それをユニットテストで記述することができる、 おそらくはそう言ってよいと思います。
※ その証明を見たことがないので断言できませんけれど、 まず間違いないと思います。

それは 「 [プログラム設計事始] メソッドの外部設計(2) 」 で書いたような、 入力としてメソッドの引数の他に外部条件があったり、 出力としてメソッドの返値の他に出力引数や外部変化があったりしても同じです。

ただし、 ユニットテストのコードから外部条件を設定したり、 外部変化を観測したりすることには、 困難が伴うことがあります。
そのときは、 工夫をして切り抜ける場合もありますし、 そうした工夫に掛けるコストがバカにならないときはユニットテストに置き換えない ( 紙の外部設計書を作る ) こともあります。

例を挙げると、 外部条件としてのシステムクロックがあります。 .NET Framework では、DateTime.Now プロパティとして簡単に得られるわけですが、 しかしながら読み出すたびに値が違います。
朝・昼・夜で違う文字列を返すメソッドを作りたいとします。 メソッドの外部設計表を書くなら、 三行で表現できてしまいます。 これをユニットテストで表現しようとすると、 どうなるでしょうか? ユニットテストを丸一日掛けて実行しますか? それとも、 ユニットテストの中で PC のクロックを強引に変更しますか? ( PC の時計をいじると、 他に影響が出そうですよね。 ユニットテストを複数スレッドで実行していたら、 てきめんでしょう。 )
これはもう、 ひとつの実装パターンだと言ってもよいかと思うのですが、 コードの各所から自由に DateTime.Now プロパティを読み出すことはルールとして禁止し、 そのかわりに、 自前でシステム・クロックを提供する部品を用意してしまいます。 そして、 ユニットテストからは、 「システム・クロック」 を自在に指定できるようにしておくと上手くいきます。

違う例として、 メソッドを呼び出すとメッセージボックスが出る場合が挙げられます。 これも、 メソッドの外部設計表には、 「○○というメッセージボックスが出る」 というようなことを書けば終わりなんですが…
ユニットテスト中にメッセージボックスが出てしまうと、 誰かがボタンをクリックするまで、 ユニットテストは止まってしまいますよね。
やろうと思えば、 ユニットテストからそのメソッドを呼び出す直前に監視用の別スレッドを起こしておき、 そこでメッセージボックスの出現とその内容をチェックし、 適切なボタンのクリックをエミュレートする… などど作り込むことは不可能ではないでしょう。
しかし、 そのような工夫は工数が膨大に掛かりそうですから、 メッセージボックスを確認する数が少ないなら目視確認にしてしまったほうが良いでしょう。
※ 確認すべき箇所が多いなら、 メッセージボックスを出すだけのメソッドに切り出して、 ユニットテスト時には、 そのメソッドが正しく呼び出されたかどうかだけチェックして、 実際のメッセージボックスは出さないようにします。

 

このように、 外部条件・外部変化があるメソッドの外部設計をユニットテストで表現しようとすると、 難しい場合があります。 その困難は、 いろいろ工夫すれば乗り越えられると思いますが、 実際の開発プロジェクトでは ( リグレッションテストも含めて考えて )、 工夫する工数を掛けるべきか、 手動テストで確認すべきか、 コストを勘案して使い分けたほうがよいでしょう。

・ メソッドの外部設計は、 厳密に記述できてしかも簡単に繰り返すことができるユニットテストで表現したほうが良い。

・ ただし、 なんでもかんでもユニットテストに置き換えれば良いというものではない。 自然言語で表現し、 確認は手動テストとしたほうが低コストな場合もありうる。 ( その代表格は GUI )

それを踏まえた上で、 次回は、 外部条件にシステム クロックを持つメソッドの外部設計をユニットテストで表現してみます。

|

« USB 3.0 ではコネクタ形状が変わる | トップページ | [NUnit 2.5] TestCaseAttribute の使いかた »

プログラミング」カテゴリの記事

コメント

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: [プログラム設計事始] メソッドの外部設計とテストファースト(2) ~ なんでもユニットテストで記述できるか?:

« USB 3.0 ではコネクタ形状が変わる | トップページ | [NUnit 2.5] TestCaseAttribute の使いかた »