tsucchi’s diary(元はてなダイアリー)

はてなダイアリー(d.hatena.ne.jp/tsucchi1022)から移行したものです

Test::More で no_plan が良くない訳

Test::More 自動試験をさらに便利にする - Perl入門〜サンプルコードによるPerl入門〜

no_planは、「テストを弱くするのでなるべく避けてください」とドキュメントにあるのですが、何が弱くなるのかよくわからない。

オイラも結構 no_plan 使ってしまうのだけどね、でもホントは良くないんだよね。exit されると、テストが途中で終了しちゃうんだよね。例を作るとこんな感じ。

#!/usr/bin/perl
use strict;
use warnings;
use Test::More "no_plan";


# 以下テスト
is( sum(1,2), 3);# => ok
is( sum('a', 0), -1); #=> ホントは NG だけど、exit されて上が ok だからテストスイートが通ってしまう


# これがテストされる関数。同一ファイル・パッケージにおいてるけど、
# 別ファイル・別パッケージにあると考えたほうが問題を認識しやすいと思う。
sub sum {
  my( $a, $b ) = @_;
  if ( $a !~ /\d+/ || $b !~ /\d+/ ) { #正数しかだめとする
    warn "invalid argument!\n";
    exit 0; #お作法としては、die するほうがいいけど、あえて exit
  }
  return $a + $b;
}

こんな感じで、意図せずテストが通ってしまいます。(↓)

% prove a.pl
a.pl .. 1/? invalid argument!
a.pl .. ok
All tests successful.
Files=1, Tests=1,  1 wallclock secs ( 0.08 usr  0.06 sys +  0.22 cusr  0.06 csys =  0.42 CPU)
Result: PASS

Test::More 自動試験をさらに便利にする - Perl入門〜サンプルコードによるPerl入門〜(コメントより)

テストの分岐ミスやexit 0 というのは、実際にどのような状況で起こるのでしょうか?
そういった経験って今までありますでしょうか?

僕の経験ではこの「exit」を2回くらいました。どちらも結構典型的なケースだと思います。

  1. 他人から引き継いだプログラム
  2. CGI で使っているライブラリのテストコードを書いているとき

1. は他人から引き継いだプログラムにテストコードが無くて、新たに自分で書いているときにハマりました。そのころは exit がテストコードを終了させることを知らなくて、かなり焦りました。

2. はたぶん最も典型的なケース。CGI だと、die すると Internal Server Error になってしまうので、エラー終了も exit を使うことが多いと思います。CGI が use しているライブラリをテストコードでも使っていると、(とくに意図せずエラーになったときに)exit されてハマることがあります。

どちらも結局原因を特定してからは力技で押し切ったのだけどね。。。1は exit を書き換え。2はテストコードでは exit しているサブルーチンを動的に書き換えて逃げました。

about Test::More::done_testing - TokuLog 改めB日記

Test::More::done_testing が導入されているわけですが、みなさんつかってますか?

と、最近の Test::More だと no_plan の代わりにテストの末尾に done_testing を書けるらしいので、これが使えるとありがたのですが。。。Perl 5.8.8 あたりだと、0.62 くらいの古いやつがバンドルされているみたいで、今の環境では使えないんだよなぁ。自分でモジュール入れる権限があれば良いのですが、今の開発環境は無いんだよねorz

done_testing が使えれば使う、テストの数があんまり増減しないなら tests をちゃんと書く、no_plan なら exit をケアする、というのが無難ながら結論になるのかなぁ。