前回の
テストモジュールの作り方
たくさんのテストを書いていくと、
テスト関数を関数内から呼び出すと期待した動作とならない
実際のテストでは、
そうなってくると、
たとえばJSONデータに指定したキーが存在することをテストするために、JSON::PP
のdecode_
の呼び出しとis
関数をまとめてtest_
を作ったとします
1: use Test::More tests => 1;
2: use JSON::PP;
3: sub test_json_key {
4: my ($json, $key, $val, $name) = @_;
5: my $ref = decode_json($json);
6: return is($ref->{$key}, $val, $name);
7: }
8: my $data = q#{ "address": "Gotanda" }#;
9: test_json_key(
10: $data, 'address',
11: 'Kichijoji',
12: 'address test'
13: );
リスト2を実行すると実際には9行目でテストが失敗がしますが、Failed test 'address test' at test_
と出力され、Test::More
にはis
を別の関数でラップしたことを知る手段がないためです。
Test::Builderを使って書きなおす
実はTest::More
をはじめとしたほとんどのテストモジュールは、Test::More
に付属するTest::Builder
というモジュールを使って作られています。先ほどの関数もTest::Builder
を使って書きなおすと正しい結果が得られます
1: use Test::More tests => 1;
2: require Test::Builder;
3: use JSON::PP;
4: sub test_json_key {
5: my ($json, $key, $val, $name) = @_;
6: my $ref = decode_json($json);
7: my $tb = Test::Builder->new;
8: return $tb->is_eq($json->{$key}, $val, $name);
9: }
10: my $data = q#{ "address": "Gotanda" }#;
11: test_json_key(
12: $data,
13: 'address',
14: 'Kichijoji',
15: 'address test'
16: );
リスト3の8行目で使用しているis_
はTest::Builder
が提供するテストメソッドで、Test::More
のis
関数と同じ機能ですTest::More
のis
関数の内部では、is_
を呼び出しています)。
今度はエラーメッセージにFailed test 'address test' at test_
と出力され、
このように、Test::Builder
のメソッドを呼び出すことで独自のテスト関数を作ることができます。また、
package Test::JSON::Key;
use parent qw/Exporter/;
our @EXPORT = qw/test_json_key/;
sub test_json_key {
...
}
独自のエラーメッセージを表示する
Test::Builder
にはok
メソッドという、Failed [test name] at [test file]line [n].
というメッセージは、
diag
メソッドと組み合わせて次のようにテスト関数を定義すれば、ok
メソッドや、is_
メソッドを内部で呼び出し、
if ($pass) { # テストが成功したとき
$tb->ok(1, $name);
} else { # テストが失敗したとき
$tb->ok(0, $name);
$tb->diag("got: $got");
$tb->diag("expected: $expected");
}
テストの数を指定する
Test::More
ではテストの数をuse Test::More tests => 42
といった形式で指定できますが、Test::Builder
と一緒に提供されているTest::Builder::Module
を使います。
package Test::MyTestModule;
use parent qw/Test::Builder::Module/;
our @EXPORT = qw/my_test/;
sub my_test { ... }
このようにTest::Builder::Module
を継承すると、Test::More
自体もTest::Builder::Module
を継承しています)。
use Test::MyTestModule tests => 42;
Test::Builder::Module
はExporter
モジュールを継承しているので、@EXPORT
で指定したmy_
関数がエクスポートされ、
Test::More
の解説でも触れましたが、done_
を使って最後にテスト数をカウントする方法がお勧めですが、Test::Builder::Module
を使って両方のスタイルに対応できるようにしておくのが良いでしょう。
Test::Testerによるテスト結果のテスト
テストモジュールにも当然テストは必要です。テストの結果は標準出力と標準エラー出力にTAP形式で出力されるので先述したTest::Output
を使ってのテストもできますが、Test::Tester
というモジュールを使うともっと簡単にテスト結果のテストができます。
Test::Tester
は、Perl 5.
よりコアモジュール入りしたテストモジュールです。Perl 5.
より前のバージョンを使っている場合は、1.
以降のTest::More
をCPANからインストールすると使えるようになります。
Test::Tester
ではTest::Builder
の主要なメソッドを置き換え、is
関数の挙動をテストするテストはリスト4のようになります。
use Test::Tester;
use Test::More;
check_test(
sub {
is(1, 2, "failure test");
diag("test end");
},
{
ok => undef,
name => "failure test",
diag => " got: '1'\n" .
" expected: '2'\n" .
"test end"
},
'is test'
);
done_testing;
また、run_
という関数も用意されています。
my ($premature, @results) = run_tests(
sub {
is(1, 1, "success test");
is(1, 2, "failure test");
}
);
is(
$result[0]->{name},
"success test",
"name test"
);
テストが開始される前に出力された文字列は$premature
に入り、@results
に入ります。あとはリスト4のcheck_
と同様にokや、name
、diag
といったハッシュキーで結果を取り出し、
このようにTest::Tester
を使えばテスト単位で結果がオブジェクトとして取り出せるため、
<続きの