TOP > プログラマ2.0日報 > 2008年05月08日

あすなろBlogger

facebookに投稿 このエントリーを含むはてなブックマーク このエントリーを含むはてなブックマーク このエントリーをはてなブックマークに追加 この記事をクリップ! livedoorclip ユーザー数 BuzzurlにブックマークBuzzurlにブックマーク この記事をtweetする

「テストファーストには反対だ!」

2008.05.08

少し前回の補足...というか、前回書いていて見かけた内容についての、ちょっとした意見...というあたりでしょうか?

要するに「テストファーストに対する反対意見」について、ということです。あ、私はテストファースト好きですよ!! ですから、「反対意見に感じる違和感みたいなもの...」が今回のテーマです。

すごく有名な「デキの悪い反対意見パロディ」として有名なものとして、「テスト・ファーストなんて嫌いだ」がありますが、これは「反対意見をパロろうとして、結果として全然面白くない...」といういささか不憫なエントリだったりします。まあここで書かれている反対意見(の根拠)に説得力がないのはパロディセンスの欠如というものでしょうから、ここで検討する意味はないですね。

テストファーストの弊害」はまともなので、こっちはマジメに検討する価値があります。このページが論拠として挙げるのは次のものです。

  1. 1. 計画性のないテストによって、テストの品質が下がる
  2. 2. 単体テストが行われず、バグが見逃される
  3. 3. 効果的でないテストが工数を浪費する
  4. 4. 読みづらいドキュメントが、修正を妨げる

このうち 4. の「テストケースが仕様を正確に明示するものだ、とは言っても、それが読みやすくまとまっているというわけではない」というあたりは私も全面的に賛成です。これはいいツールを作る...とか考えて、javadoc に統合できないかしら....テストケースに記述されたテスト内容が、いつもの javadoc に反映したらすごくイイでしょ。とはいえ、そのテスト内容をうまく抽出して記述できないと意味がないので、そこは考えどころですが....

しかし、その他の3点にはかなり違和感があります。それは、

テストファースト=開発と単体テストを一緒にやってしまう開発手法

とどうやら捉えているらしい...というところでしょう。あれ、テストファーストのテストって、どっちかいうと、

よりよい仕様を探っていくための、設計手段としてのテスト

というものじゃなかったっけ。ですから、作ったコードが(外部的な)仕様を満たしているかどうかテストするテスト、とは全然独立なもの、とさえ思います...まあ、外部的な仕様が完全に決まっているプログラムだったら、テストファーストを採用する必要性なんて全然ない...とは感じませんか?(まあダブって単体テストしても害は何もないと思いますよ、苦笑) 「テストファースト=今風の契約主導設計」というところでしょうか?

ですから、私が感じるところの、最大のテストファーストのメリットは実はですね、

インターフェイスが洗練される

ということなのです....

普通に書いていると、「直接呼び出すところでうまく出来ればいいや...」という感じで場当たり的なインターフェイスを作っちゃうこともないわけではないですが、テストファーストだと「テストが明快にできるインターフェイス」をどうしても優先することになります。でしかも、ほとんどの場合、

テストしやすいインターフェイスは良いインターフェイス

だったりするわけです.....テストケースとは、プライオリティのかなり高いクライアントコードなのです。

テストファーストで書けば「呼び出し順に依存するインターフェイス」のような悪い(明示的でないルールを持った)利用規約をあえて採用するのはかなり恥ずかしい、と感じるようになります。

Target target = new Target();
target.setMap( secretMap );
int ret = target.getTreasure();

上の例のような、あるメソッドが動くのに必要な情報を、テスト前にセッタでセットする必要がある(←明示的でないルール)のを止めて、引数でその情報を渡すように変更したらどうでしょう?

Target target = new Target();
int ret = target.getTreasure( secretMap );

あるいは、渡す情報がその Target クラスにとって本質的なものであるのならば、コンストラクタで渡すのも良いでしょう。

Target target = new Target( secretMap );
int ret = target.getTreasure();

あるいは、これがまったく内部的な情報を使わないのであれば、思い切って static メソッドにすべきなのかもしれません....

int ret = Target.getTreasure( secretMap );

というように、テストファーストは、インターフェイスについて考える「もう一つのクライアントコード」としての働きを持ちます。これは特に「再利用を考えたライブラリ的なプログラム」では、「より使いやすいインターフェイス」であって欲しいですから、それをあらかじめテストケースとして考えておくようなものなのです!

ですから、逆に言えば、こういう場合にはテストファーストはあまり意味がないですね!

  1. 1. 明快に記述された外部仕様を持つ場合 → 今までの理想ケースですから、あえて変える必要はないでしょう...
  2. 2. 使い捨てで再利用する可能性が低いコードの場合 → 一度書いたコードを「多面的に使う」可能性がないのならば、あえて手間のかかる工程を取る必要はないでしょう。
  3. 3. インターフェイスを変更するのが政治的にやりにくい場合 → 「精度はともかくとしてとりあえず動いているコード」を要求され、それを使う人が今まさにいる状態で、よりよく改善している場合は、簡単に「前のインターフェイスは良くないですから、新しいインターフェイスを使いなさい」とは言えません....この場合インターフェイスの互換性を守る必要が出てしまいます。

まあ、「銀の弾丸はない」のがアタリマエです。テストファーストも適材適所、です。

投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.08 21:28

カレンダー

<< 2008年05月 >>

        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

最新のエントリー

最新のトラックバック

最新のコメント

Tag

バックナンバー