Test Anything Protocol
Perlは非常にテストを重視している言語です。連載第14回ではPerl本体のテスト数がどのように推移してきたかを、
たとえば、
#!perl
use strict;
print "1..1\n";
print $] >= 5.006 ? "ok 1\n" : "not ok 1\n";
もっとも、
Test::SimpleとTest::More
おそらく多くの方が真っ先に思いつくのはこのような書き方でしょう。
#!perl
use strict;
use Test::More tests => 1;
ok($] >= 5.006);
上の例とほぼ一対一対応していますから特に説明は不要と思いますが、
#!perl
use strict;
use Test::Simple tests => 1;
ok($] >= 5.006);
もう少しTest::Moreらしい書き方をすると、
#!perl
use strict;
use Test::More tests => 1;
cmp_ok($], '>=', 5.006);
両者の違いはテストに失敗したときの出力にあるのでした。ためしに不等号の向きを反対にして、
> prove test_ok.t test_ok.t .. test_ok.t .. 1/1 # Failed test at test_ok.t line 4. # Looks like you failed 1 test of 1. test_ok.t .. Dubious, test returned 1 (wstat 256, 0x100) Failed 1/1 subtests
cmp_
> prove test_cmp_ok.t test_cmp_ok.t .. test_cmp_ok.t .. 1/1 # Failed test at test_cmp_ok.t line 4. # '5.008009' #
もちろんこのような情報はテストの説明文のなかに埋め込むこともできます
#!perl
use strict;
use Test::More tests => 1;
ok($] >= 5.006, "Perl version: $]");
また、
ok($] >= 5.006) or diag "Perl version: $]";
cmp_
Test::Moreで利用可能なテスト
Test::Moreにはcmp_
is( $] => 5.006);
isnt($] => 5.006);
正規表現の比較も、
like( $] => qr/5\.006/);
unlike($] => qr/5\.006/);
> prove test_like.t test_like.t .. test_like.t .. 1/1 # Failed test at test_like.t line 4. # '5.008009' # doesn't match '(?-xism:5.006)' # Looks like you failed 1 test of 1.
リファレンスを使った複雑なデータはis_
is_deeply({ foo => 'bar' }, { foo => 'baz' });
> prove test_deeply.t test_deeply.t .. test_deeply.t .. 1/1 # Failed test at test_deeply.t line 4. # Structures begin differing at: # $got->{foo} = 'bar' # $expected->{foo} = 'baz' # Looks like you failed 1 test of 1.
Test::Moreにはほかにも、
Test::Most
Test::MoreはPerl 5.
そのひとつの対策として用意されているのが、
これは氏が2008年にテストモジュールの利用動向を分析して選んだ利用頻度の高い5つのテストモジュール
たとえば、
use strict;
use Test::Most tests => 1;
sub func { die unless defined $_[0] }
dies_ok { func(undef) } 'undef is not allowed';
dieしないことを確認したい場合は同じくTest::Exception由来のlives_
use strict;
use Test::Most tests => 1;
sub func { die unless defined $_[0] }
lives_ok { func(0) } '0 is acceptable';
入力に問題がある場合に正しく警告が出るか確認したい場合はTest::Warn経由のwarning_
use strict;
use warnings;
use Test::Most tests => 2;
warning_like { '' . undef } qr/uninitialized/;
warnings_exist { warn undef } qr/something's wrong/;
Test::Differences由来のeq_
use strict;
use Test::Most tests => 1;
eq_or_diff(['foo', 'bar', 'baz'], ['foo', 'baa', 'baz']);
> prove test_diff.t test_diff.t .. test_diff.t .. 1/1 # Failed test at test_diff.t line 4. # +----+-----+----------+ # | Elt|Got |Expected | # +----+-----+----------+ # | 0|foo |foo | # * 1|bar |baa * # | 2|baz |baz | # +----+-----+----------+ # Looks like you failed 1 test of 1.
さらに柔軟な比較を行いたい場合は、
#!perl
use strict;
use Test::Most;
use DBI;
my $dbh = DBI->connect('dbi:SQLite::memory:');
$dbh->do('create table foo (id, pass, status)');
$dbh->do('insert into foo values(?,?,?)', undef, qw/ishigaki *** 1/);
$dbh->do('insert into foo values(?,?,?)', undef, qw/charsbar *** 0/);
my $people = $dbh->selectall_arrayref('select * from foo', {Slice => +{}});
plan tests => scalar @$people;
foreach my $person (@$people) {
cmp_deeply(
$person,
{
id => re('^\w+$'), # id
pass => ignore(), # pass
status => any(0, 1), # status
},
);
}
CPANにはほかにも長文のテキストの比較に特化したTest::LongStringやバイナリデータの比較に特化したTest::BinaryData、