単体テストを信用するな(1)(2)

システム開発をやる上で、避けては通れないフェーズが「テスト」。
おそらく「テスト」と聞くだけでげんなりする人も多いかと思います。
今回は、最も初期に行なうテストである「単体テスト(UT)」について、
実施する目的や方法、品質面で考慮することなどを書いてみます。

まず、テストの目的について。
実装フェーズではプログラマがせっせとプログラム作成を進めるわけですが、
人間のやることなので、当然ながらバグが発生します。
もちろんバグは修正するのですが、パッと見では分からないような細かいバグの場合、
リリースまで誰も気づかず…なんてことも起こりかねません。
そういう事態を防ぐためにテストを行ない、バグを洗い出して端から修正して行くわけです。

さて、今回のテーマである単体テストですが、
これは実装を行なったプログラマ自身が、
自分の作成したプログラムをテストする工程を指すことが多いようです。
ほとんどの場合、プログラマは自分の担当する機能を一つずつ実装するので、
テストも一機能(=単体:Unit)ずつ行うことになります。

その辺を踏まえて、今回の主題である「単体テストを信用するな」という話を。

前述の通り、単体テストは「自分が作ったものを自分でテスト」するのが基本です。
自分が作ったプログラムですから、その挙動は十分すぎるほど把握しているはずなので、
想定外の動きをすればすぐに「バグだ!」と気づくことでしょう。

しかし、ここには大きな落とし穴があります。
それは、プログラマ自身が「これが正しい」と考えている動きが、
必ずしも設計者の意図と一致していない可能性があるからです。

※この記事は、[単体テストを信用するな(1)]の続きです。
(1)を読んでいない人は、先にそちらを読んでください。


大抵のプロジェクトでは、プログラマは「設計書に書かれた日本語」を頼りに実装を進めます。
多くの場合、設計者の意図は正しくプログラマに伝達されるのですが、
設計書に少しでも曖昧な表現が紛れ込んでいた場合、正しく伝達されるとは限りません。
あるいは(酷い言い方ですが)人間は出来るだけ楽な道を進もうとするので、
無意識のうちに、自分の都合のいい解釈をしてしまうこともあるでしょう。

このような場合、プログラマは自分の認識が正しいと信じて疑わないわけですから、
プログラムが設計者の意図と違う動きをしていても、単体テストでは検出できないことになります。
プログラマからしてみれば、「自分の意図した通りに動いている」わけですからね。

単体テストで検出できないバグは、次の結合テスト(IT)で回収することになります。
結合テストの説明はまた次回にしますが、単体テストとの大きな違いは
「テストは設計者が行なう」という点です。
今度は設計者自身がテストするのですから、設計者の意図した通りに動かなければ
すぐにバグを見つけ出すことが出来ます。

さて、私が「単体テストを信用するな」と書いた理由は理解していただけたでしょうか?
結局の所、単体テストだけではバグは取りきれないのです。
さらに言ってしまうと、どの部分が設計者の意図とズレているかなんて分からないのですから、
実質的には「テストは何も済んでいない」のと同じだと言うことです。
そのため結合テストでは、単体テストで一度確認した項目についても、
再度テストを行う必要があります。

…では、単体テストを行うことに意味は無いのでしょうか?いいえ、そんなことはありません。
もし単体テストを行なわなかったら、結合テストでシステムエラーが頻発し、
テストが進まなくなることでしょう。それを予め防ぐことは非常に重要です。

若干酷い言い方かもしれませんが、単体テストとは結合テストを行なうための「地ならし」であり、
システムエラーなどのプログラム的なバグを取り除くことを主眼とすべきなのです。

時々この辺の話が理解できていないSEがいて、
「単体テストで細かいテストは済んでいるから、結合テストでは大まかな動きを見れば良い」
などと言い出す人が居ますが、これは問題アリです。

例えば日付を設定するデータ更新処理で、間違った値が設定されたらどうなるでしょうか?
プログラマが「この値で更新するのが正しい」と思い込んでいたら、単体テストは通ります。
そして、結合テストでは「細かいこと」と一蹴してテストを行わなかったら…。
リリース前に、たまたま誰かが見つけてくれるのを祈るばかりです。

http://brandnewdays.jp/column/se002_1.html
http://brandnewdays.jp/column/se002_2.html