ゴミ箱の中のメモ帳

まだ見ぬ息子たちへ綴る手記

テストを本当に書いてる奴なんているんだな

なんだか数年前からTDD(テスト駆動開発)だの、エクストリームプログラミングだの、テストファーストだの騒がれ、テストを書くことの重要性を謳う記事が多く書かれているのを目にする。

 私はそれをギャグとして受け取って生活してきたのだが、どうも本気でそれに取り組み、それが重要だと思っている連中がいるようだ。そしてそれを本気で信じているからこそ宗教と同じように布教活動に勤しみ、その記事を書いていたようだ。

 確かに私もテストは大事だと考えている。小さなコードであれば今でもプリントデバッグが基本になるが、そこそこ大きなコードになればプリントでバッグでは追いきれない。ちょっとした変更をする度にプリントを挿入してデバッグするのは無駄な労力でしか無い。

 だからこそそういったコードはテストを書き動作確認を自動化するのであるが、そのテストを手動で書いているバカがいることに驚いた。

 

 

経験ゼロでもできるプログラミング現場の単体テスト

経験ゼロでもできるプログラミング現場の単体テスト

 

 

====

私の知り合いの会社のサポートに呼ばれた時に、アホの社長が「品質管理部」を立ち上げたと自慢してきた。

 品質管理部とは何をする部署なのかわからなかったが、どうも「コードの品質」を確保するためのテストを書きコードにいちゃもんをつける部署であるらしい。

 その社長は自分のことをCEOと呼ぶようなバカなのでそのような考えに至ったのであろうが、どうも調べてみると同じようなことをしている中小企業があるようだ。

 なぜ「テストを書く人間」が必要なのかがわからないし、そもそもになぜコードを書く人間とテストを書く人間を完全に分離する必要があるのか。そしてなによりなぜその部署のために新たな人間を雇ったのか。

 

どうも「手動でテストを書く」と言う事が馬鹿らしくて仕方が無い。先に書いたようにそれはギャグかと思っていた。

 確かに変質的なテストや、定形でないテストであればそれを手動で書くこともある。だが、関数に値を渡して戻り値をチェックするようなテストや、分岐や例外テスト、結合テストのようなものはそれ自体も自動化しなければ意味がない。

 簡単にはxUnitのようなテストを手動で書いているのが馬鹿だということだ。


この行為が馬鹿げた事だとわからないというのであればあなたはテストというものがなにかわかっていない可能性がある。例えばそれを手動で書くという事は、テスト自体にもバグが含まれる可能性が多いにあるという事だ。

 であればテストコードにもテストが必要になり、そのテストコードのテストコードも手動で書いているのであればそれにもテストコードが必要になる。これはわかってもらえるだろう。

 そういったテストを手動で書いている人が大いに勘違いしているであろうことは、「テストが正しい」と思っていることだろう。例えば境界値テストにしてもその「境界値」を誤って設定してしまっていたり、そもそもタイプミスで境界値エラーを合格としてしまう可能性もある。

 そうすればテストが通り続ける限り、その境界値テストは間違ったまま、何も疑われることがなく、間違った動作を続けることになる。

 テストとはそもそもそういった人間の誤りを見つけるために書くコードであるのに、それを人間が書くという事自体が馬鹿らしいという事はわからないのか。人間が書き続ける限り正しいテストコードというものは生み出されない。

 ヒューマンエラーをチェックするためのコードにもヒューマンエラーが潜り込んでしまう可能性があるのであれば、それは問題を増やしていることにしかならない。

 

多少大げさに言ってしまったがテストとはそういうものだ。テストの生成自体も自動化しなければ意味がない上にテスト自体の失敗が大いにあり得る。

 だがテストコードの生成を自動化すると言っても、結局はその自動化エンジンのコードも人間が書くことには変わりないという点ではどちらにしろ同じ事だ。手動でテストを書くことで、テスト自体にもバグを忍ばせている。

 例えば私が昔に書いていたテストは、関数(クラス、メソッド)の頭にその関数の期待する動作(パラメータ)を書いておき、それをテスト生成エンジンがパースしてテストコードを生成する。そうすればテストを手動で書くことで起きるタイプミスは起こりえない。何千何万というテストを手動で書くとそういったミスもかなりの数が起こり得るが、自動化では起こりえない。

 確かに関数の頭に書いたパラメータを誤って記述するタイプミスもあるが、その周辺も含めて境界値テストとして生成するエンジンにしていればタイプミスに気がつける可能性が高い。そしてそんなミスが可能性としてあるにしても、テストを手動で書くことに比べればパラメータの正当性の確認など極僅かな手間でしか無い。

 そしてテストコード生成エンジンが生成するコードが正しいかどうかのテストのみ人間が書けば、ひとつのプログラムのテストのみを人間が書けば良いだけになる。今後どのようなコードを書こうと、そのテスト生成エンジンがサポートするテストである限り新たなテストを書く必要はない。

 新たなテストが必要になったとしても、それをエンジンに組み込めば今後のコードにそのまま適応できるのでテスト自体の実装は一度で済むことになる。

 だがこんな単純な仕組みにせず、手動でテストを書いている人間がいるという事だ。先の会社の例でも、そのテストを手動で書き続けるために人件費をかけ、エラーを増加させるようだ。

 もし「品質管理部」と言うものを立ち上げる必要があるとすれば、それはテストコード生成エンジンを制作するための部署にすべきだろう。そしてそれが汎用的なものなのであればそれ自体も製品として売り出すことができる。

 こんなこともわからない人間には、そもそもまともなテストコードがかけるとも思えない。

 

このテストコードの例としてはSQLiteが非常に参考になるだろう。SQLiteのテストは「How SQLite Is Tested」のページに書かれているので読んで欲しい。そして何より、そのSQLiteのコードを読み、そのテストコード自体も読んで欲しい。

 SQLite本体のコードはSQLite3.8.6で8万9900行だ。インターフェイスに大部分が割かれているのでこの程度であれば暇暇にコードを追いかけることは出来るだろう。そしてそんなコードのテストコードの行数は9149万3000行だ。

 本体コードのおよそ1018倍の分量のテストコードがある。私が見てきたテストは大きいものでも本体コードの10倍程度であるが、それからしても規模のデカさがわかるだろう。

 テストの詳細もそのページに書かれているので読んで欲しいが、レガシーなテストコードがあるとしつつも、主にはパラメータからテストコードが生成される様になっている。そしてSQLiteの信頼性の証明としてもMySQLOracleのようなデータベースと互換性のある結果が返されるかどうか1.12GBのデータを用いて720万クエリがテストされる。

 これをもし自動化しないのであれば、約1億行のテストコードを手動で書く人間が必要になるのだ。そんなことが非現実的であることはテストコードを手動で書いているあなたにもわかるだろう。そしてそのテストコードの信頼性の確保など出来る訳がない。

 だが手動でテストを書くということは、まさにコレを主導で行っているのと同じことだ。

 そしてこれは自動化されているからこそ信頼性を確保できているという良い例だろう。


もしあなたがテストコードを手動で書いているのであれば、そのテストコードを書く時間で是非ともテストコード生成エンジンを書いて欲しい。そうすればあなたのプログラマ人生が何十倍、何百倍になるだろう。テストコードほど書いていて虚しく、イライラし、時間がかかるものはない。

 それを省略出来るだけで、今後どれだけの時間が、寿命があなたに確保されるだろうか。

 そしてもちろんコードのバグを見つけられる可能性も大きく向上することになる。