Perlにおける例外
プログラムを組む上で例外の取り扱いは非常に重要です。
- 有るはずのファイルが存在しない
- データベースのレコード関係が不整合を起こしている
- 渡されるハズのパラメータが存在しない 等々
Perlにも例外処理の仕組みが存在します。簡単にまとめる以下の様になります。
- スクリプト本体からの例外送出はdie関数を使う。例外の内容と例外が送出された行が表示される。
- モジュールからの例外送出はCarpモジュールのcroak関数を使う。モジュールを呼び出した側の行数が表示される。
- 例外はeval関数を使うとキャッチできる。evalが無ければスクリプトの実行は中断する。
例外の発生有無やの内容は特殊変数$@で判断する。
die "Raise Exception from this script because...";
package XXX;
use Carp;
croak "Raise Exception from module XXX because...";
eval {
die "Raise Exception from this script because...";
};
if ($@) {
print $@;
}
例外をテストするには...
テストコードの中で例外が発生すると、テストコードも単なるPerlのスクリプトなのでevalでキャッチしなければテストコード自体がただちに終了してしまいます。しかしこれではテストになりません。
しかし、例外をキャッチするためにeval関数を使うと、テストコードが見にくくになってしまいます。この問題を解決してくれるのがTest::Exceptionモジュールです。
Test::Exceptionモジュール
Test::ExceptionはAdrian Howardさんが作った例外処理を扱うためのテストモジュールです。標準モジュールではありませんが、dieや、croakを使うモジュールをテストする時には無くてはならないモジュールです。
標準モジュールではないので、CPANなどからインストールして下さい。
基本的な書式
実際の使い方
テストコードの実行結果
メインとなる関数は、例外をキャッチするthrows_ok関数です。この様な書式で使います。
throws_ok BLOCK REGEX, TEST_DESCRIPTION
throws_ok BLOCK CLASS, TEST_DESCRIPTION
まずはテストするモジュールのサンプルです。関数の引数が省略されていると例外送出します。まぁ、ありがちなチェックですね。
$ more Exception_Module.pm
package Exception_Module;
use strict;
use warnings;
use Carp;
sub function {
my $param = shift;
if (! defined $param) {
croak "No Param!";
}
return "OK!";
}
1;
次にテストコードを見てみましょう。
$ more exception.t
#!/usr/bin/env perl
use strict;
use warnings;
use Test::Exception tests => 2;
use Exception_Module;
throws_ok {Exception_Module::function()} qr/No Param/, "No Param Test Pattern";
lives_ok {Exception_Module::function(1)} "OK Param Test Pattern";
最初のテストではcroakで例外が送出されますが、それをTest::Exceptionがキャッチしてくれます(テストコードの中でdieやcroakが発生し、誰もevalでキャッチしないとテストコード自体は異常終了してしまいます)。その上、croakが発出したメッセージ内容をチェックし、想定した例外である事も同時に確認します。当然、ただ例外が出ればいいという訳ではなく、想定した通りの例外である事を確認できなければ意味がありませんから。
次のテストでは例外が発生しない事を確認しています...が、通常は普通の機能テストを行うと思うので、わざわざlives_ok関数を使う場面はイマイチ分からないですね。
さきほどのテストコードを実行してみましょう。
$ prove exception.t -v
excption.t ..
1..2
ok 1 - No Param Test Pattern
ok 2 - OK Param Test Pattern
ok
All tests successful.
Files=1, Tests=2, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.02 cusr 0.00 csys = 0.04 CPU)
Result: PASS
まぁ、当たり前ですが全てテストが通りました。これで例外のテストが完了です。
おわりに
例外が送出されるパターンをテストするのに、わざわざ自分でevalを書いて回るとテストコードがとても見にくくなるので、Test::Excptionは必須のテストモジュールと言えます。早く標準モジュール入りすればいいのにといつも思います。

コメントする