Perl Hackers Hub

第36回 Perlのテストモジュールの使い方・作り方-Test::More,Test::Builder,Test::Stream,そしてPerl 6(1)

この記事を読むのに必要な時間:およそ 4.5 分

本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーは,Perl関連のイベント ⁠吉祥寺.pm」の主催などで知られるMagnolia.Kさんで,テーマは「テストモジュールの使い方・作り方」です。

本稿のサンプルコードは,WEB+DB PRESS Vol.90のサポートサイトから入手できます。

Perlにおけるテスト

読者のみなさんはテストを書いていますか。

Perlは昔からテストをとても大事にしてきた言語です。テストを書くために必要なテストモジュールはコアモジュールとしてPerl本体と一緒にインストールされていて,すぐにテストが書ける環境が用意されています。CPANにアップされているモジュールには,たいてい十分な量のテストが用意されていて,安心して使うことができます(動くかどうかもわからないモジュールは使えないですよね)⁠

今回はテストモジュールの使い方や,テストモジュールの作り方を通じて,Perlにおけるテストの方法を解説します。また,2015年のクリスマスに正式版がリリースされたPerl 6でのテストの方法についても解説します。

なお,以降のコードは,特に注釈がない限りPerl 5.14.0以降で動作するように書かれており,Perl 5.22.0で動作確認を行いました。

また,紙幅の都合でuse strictと,use warningsはすべて省略していますが,実際にコードを試すときには必ず付けてください。

テストモジュールの使い方

まずはテストモジュールの使い方とテストの実行方法を解説します。

Test::More─⁠─Perlのテストの基本

テストモジュールの中で最も基本的な機能を提供するモジュールがTest::Moreです。Test::MoreはコアモジュールとしてPerl本体と一緒にインストールされています。

Test::Moreを使ったテスト

最初のテストとして,Perlの組込み関数であるlength関数注1の挙動を確認するlength_test.t注2というテストを書いてみますリスト1)⁠

リスト1 length_test.t

1: use Test::More;
2: is(length("perl"), 4, "length test");
3: is(length(undef), 0, "undef test");
4: done_testing;

1行目は,テストモジュールのTest::Moreを使用するための宣言です。以降で使用するisという関数が使えるようになります。

2行目は,Test::Moreis関数を使ってテストを実行しています。is関数は引数を3つ取り,1つ目はテストの対象の値(主に関数やメソッドの戻り値)⁠2つ目は期待する値,3つ目はテストの名前を指定します。ここではlength("perl")の戻り値と,期待する値(4)を比較し,テストの名前としてlength testを指定しています。

3行目では再びis関数を使って今度はlength(undef)と,0を比較しています。なお,length(undef)は実際にはundefを返すので,このテストは失敗します(詳細はのちほど説明します)⁠

最後の4行目では,テストがすべて終わったことを宣言するため,Test::Moredone_testing関数を呼び出しています。

注1)
引数で与えられた文字列の文字数をカウントする関数です。
注2)
テストの拡張子は.pl.pmではなく,.tを使用します。
テストの実行

リスト1を通常のPerlのプログラムと同じように実行してください。

length_test.tの実行

$ perl length_test.t

ok 1 - length test ―(1)

not ok 2 - undef test ―(2)
#   Failed test 'undef test' 
#   at length_test.t line 3. 
#          got: undef        ―(3)
#     expected: '0'          
1..2  ―(4)
# Looks like you failed 1 test of 2. ―(5)

テストの結果が出力されました。1行ずつ見ていきましょう。

(1)okと出力されていますが,これは1つ目のテストが成功したことを示しています。後ろに続く数字1と文字列は,そのテストが実行された順序を示す連番と,isに渡したテストの名前です。

(2)not okと出力されていますが,これは2つ目のテストが失敗したことを示しています。その後ろはテストが成功したときと同様にテストの連番とテストの名前が表示されています。

(3)では,テストが失敗した原因の詳細が出力されています。最初にテストが失敗した箇所のファイル名と行番号length_test.t line 3が出力され,続けて実際に得られた値gotと期待した値expectedが出力されています。この内容をもとにテストが失敗した原因を解析します。

すべてのテストが終わりdone_testingが実行されると,(4)でそれまで実行したテストの数が1..[テスト数]という形式で出力されます。

失敗したテストがあるとテストプログラムが終了するタイミングで,(5)のように失敗したテストの数が出力されます。

このようにPerlでは,テスト対象と期待する値を比較し,期待どおりならばテストが成功し,期待した内容と異なればテストが失敗する,というスタイルでテストを書いていきます。先ほどのis関数は最も基本的なテストのための関数(テスト関数)ですが,このほかにも目的に合わせてさまざまなテスト関数が用意されています。以降ではよく使うテスト関数と,Test::Moreが提供するそのほかの機能を解説します。

like─⁠─正規表現によるテスト

likeは正規表現を使うテスト関数です。引数の2番目に正規表現へのリファレンスを渡す点がisと異なります。

like(
    "perl-5.22.0.tar.gz",
    qr/perl-5\.\d+\.\d+\.tar\.gz/,
    "archive name test"
);
cmp_ok─⁠─任意の演算子を使った比較テスト

cmp_okは指定した演算子で比較を行うテスト関数です。数値の大小比較など,任意の演算子を使って比較したい場合に使います。

cmp_ok(1 / 10, '<', 0.11, "division test");
is_deeply─⁠─リファレンスのテスト

is_deeplyはリファレンス用のテスト関数です。2つのリファレンスをたどりながら比較を行います。

sub create_person {
    return { name => $_[0], age => $_[1] }
}
is_deeply(
    create_person( "James", "30" ),
    { age => "30", name => "James"},
    "person object test"
);

リファレンスの先に一致しない箇所があるとテストが失敗し,その不一致箇所が出力されます。

著者プロフィール

Magnolia.K

「吉祥寺.pm」というイベントを主催したり,気ままにコードを書いたりしています。Perlが好きですが,最近はScalaにも興味が出てきています。

コメント

コメントの記入