@nqounetです。

今日はYAPC::Asiaの0日目ですね!

さて、先日CPAN Authorになったばかりなのですが、自分でもびっくりするほどテストコードを書くようになってきました。

例外(致命的なエラー)をテストするにはTest::Fatalがとても書きやすい(と私は思う)のですが、意外と日本語の情報がなかったので書いてみようと思います。

テスト大事ですよ

テストは大事ですよ、というような話は今更言うことでもないと思うのですが、モジュールを書くことによってそれを実感できたのが、CPAN Authorになったことよりももっと収穫でした。

テストコードも読んでみよう

まず何より他の人(モジュール)のテストコードをよく読むようになったことです。

これまでは、使い方の実例という位置付けで、使い方を確認する程度では見ていました。

今は、全体的にどんなテストをしているのか、こういうメソッドはどうやってテストしているのか、というような気持ちで見るようになっています。

そうすると不思議なもので、テスト用のモジュールについてもよく目に入るようになってきました。

例外テストの基本形はeval

例外が発生するとプログラムが止まってしまうので、evalを使って例外を補足します。

evalの中で発生したエラーは「$@」に入りますので、テストを書くときはこんな感じになります。

1
2
3
4
5
6
7
8
use strict;
use Test::More 0.98;

like 'a', qr/a/, q{ like };
eval {die 'a'};
like $@, qr/a/, q{ like eval };

done_testing;

$@がqr/a/でマッチすればテストがOKなのですが、$@が何なのかが直感的に頭に入ってこない感じです。

まあ仕方ないですよね。

Test::Exceptionの時代

evalのテストは結構書くのが面倒なので、検索で見つけたTest::Exceptionを使ってみたのですが、書いてみると何か気持ち悪いなと思いました。

何がそう感じさせるのか考えてみると、カンマが違うということに気づきました。

例えばlikeは引数がカンマ区切りなのですが、throws_okは、例外を発生させるコードと検証用のコードの間にはカンマを書きません。

1
2
3
4
5
6
7
8
use strict;
use Test::More 0.98;
use Test::Exception;

like 'a' , qr/a/, q{ like };
throws_ok {die 'a'} qr/a/, q{ throws_ok };

done_testing;

慣れればこれで良いのかもしれませんが、*_okという書き方なのに引数の渡し方が違うのが、常に頭の隅で引っかかりました。

で、ある時Test::Fatalを知って、即乗り換えました。

Test::Fatal

Test::Fatalを使うと「exception」という関数が使えるようになります。

これを使うと、例外が発生するコードブロックを、テストの中に直接書くことができます。

1
2
3
4
5
6
7
8
use strict;
use Test::More 0.98;
use Test::Fatal;

like 'a' , qr/a/, q{ like };
like exception {die 'a'}, qr/a/, q{ like exception };

done_testing;

書き方としては、evalのブロックを直接テストの中に書くことができるようなイメージです。

exceptionを使うことで、テストの書き方を変えずに書くことができるようになりました。

ちなみに、例外が発生しない、というテストを書く場合はこんな感じで書くことができます。

1
is exception {'a'}, undef, q{ live };

個人的には便利だと思うのですが、如何でしょうか?