ぐらめぬ・ぜぷつぇんのはてダ(2007 to 2011)

2007年~2011年ごろまで はてなダイアリー に書いてた記事を引っ越してきました。

テスト駆動開発に対する素朴な疑問

雑誌やWeb記事などを読み、何度か局所的にxUnitを採り入れてみたことがある。また、XhwlayやPseudo_Blockについてはテスト駆動・・・とは言えないまでも、外部からみた振る舞いをチェックする為に、SimpleTestユニットテストを採り入れている。

で、いつもいつも疑問に思うのだけれど・・・なんか、雑誌とかWeb記事で紹介されているユニットテストって、「最初から上手く行って当たり前」な条件で作られているような気がして・・・。

どういう事かというと、何となくなんだけど。異常系のエラーを確認していない。
・・・ような、気がする。「DBに接続できなければエラーログ(エラーコードはXX)を出力すること」など。

もうちょっとかみ砕いて言えば、「観測」の問題のような気がする。テストはとどのつまり、観測者が居て成り立つ。観測者が、対象の振る舞いを見て、その結果から「この動きはオッケー。」「この動きはNG。」と判別する。

で、xUnitというか機械的なテストの場合は、この「観測者」をプログラムに任せるということだと自分は認識している。

そうなると、プログラムと人間との間では当然「観測項目」の得手不得手が出てくる筈。
例えば、関数の戻り値が0であること、というような観測項目はプログラム側が当然得意だろう。
しかし、DB接続に失敗したらログを出力すること(またログのフォーマットは仕様通りであること)や、ソケット接続中にいきなりLANケーブルが抜けたら、○○回リトライ後にごにょごにょ・・・というようなレベルになったら人間様が確認した方が断然確実である。
というかプログラム側でどうやって観測させるんだ?という話になる。

LANケーブルが抜けたら、という例でも出てきたが、そう、テスト対象の環境についても。前提条件についても、プログラム側で整えられるモノと、あまりにきわどすぎて人間でないと整えられないものがある。例えば複数のプログラムが同時に走ったときのDBのレコードロックの制御などだ。しかも、二つのSQLを発行する間でのロック競合。詳細な例は省くけど、以前やった時はテーブルのLOCK/UNLOCKを手動でSQLのコンソールから叩き、確認した。

よく雑誌やWeb記事では、レコード追加した結果がtrueであること、というのを判別する為のテストは良く載っている。ところが、レコードを追加するためにロックがかかり、ちょうどその真っ最中にDBが落ちてしまった場合・・・(そこまで考える必要はあるのか?というツッコミが入りそうだけど、インフラ系の通信処理の場合はそこまで考えないとプログラムの挙動に責任を持てないので、実際に試験する必要があります。)などのテストコードは見かけたことが無い。

そりゃそうだ。そもそもそうした外部条件の実装や、それによるログのチェック(人間であれば、UNIXならtailコマンドでチェックしていれば一発)という観測行為が、プログラムではひどく、不得手だからだ。

どうも、テスト駆動開発を推奨していたり、xUnitの使い方を紹介していたりするリソースにはこうした視点が抜け落ちているような気がしてならない。

フレームワークやライブラリは、利便性と引き替えに開発者の自由を奪う。

となると、テスティングフレームワークは、機械的な繰り返しによる利便性と引き替えに、人間でしかなしえない外部条件の実装や観測項目を奪うのではないだろうか。

奪うとかいうと悪い言い回しになってしまうが、要は、トレードオフになっているのでは、と言いたい。

テスティングフレームワークにとって扱いやすい外部条件や、それによる機械的な繰り返しテスト。こういうのに適した領域では、確かにxUnitなどによる機械的な繰り返しテストの恩恵を享受できるのだろう。
一方で、タイミング的なものやプログラミングだけではどうしても実装できない外部条件を要する試験。あるいは人間が観測した方が速い、又は人間でしか観測できない項目を有する試験。こうした領域については、テスティングフレームワークで無理矢理ねじ込むよりは、素直に人間様が確認した方が速いのだろう。

・・・うん、多分、そう。きっと、そう。