読者です 読者をやめる 読者になる 読者になる

ぱいぱいにっき

Pythonが好きすぎるけれど、今からPerlを好きになりますにっき

SYNOPSISのコメントを使ってテストするTest::Synopsis::Expectation

この記事はPerl Advent Calendar 2013の16日目の記事です。

Test::Synopsis::Expectation

Perlのモジュールを作る際に便利そうな少し変わったモジュール、Test::Synopsis::Expectationを使ってみます。


その前にテスト対象のモジュールを作ります。ひな形作成に便利なMinillaを使ってスケルトンを作成します。

$ minil new AwesomeTarget

そこで出来たAwesomeTarget/lib/AwesomeTarget.pmを以下のようにいじります。

package AwesomeTarget;
use strict;
use warnings;

sub plusplus {
    my ($class, $num) = @_;

    return ++$num;
}

1;

なんのことはない、ただ++するだけのクラスメソッドですね。
さて、こいつのテストコードを書きます。
AwesomeTarget/t/01_basic.tに以下のように書きます。

use strict;
use warnings;

use Test::More;

use AwesomeTarget;

is (AwesomeTarget->plusplus(1), 2);

done_testing();

そんでもってproveで実行してみます。

$ prove -l
t/00_compile.t .. ok
t/01_basic.t .... ok
All tests successful.

んまあここまでは一緒。さてTest::Synopsis::Expectationを使っていきましょう。習うより慣れろです。なんかドキュメントちょっと分かりにくいんですけれど、つまりはSYNOPSISによしなにコメントを書くと勝手にテストしてくれるってことです!!!!!マジか!!!!!!!!!!!!!!!!

AwesomeTarget.pmにSYNOPSISを追加します。

=head1 SYNOPSIS

    use AwesomeTarget;
    AwesomeTarget->plusplus(1); # => 2

=cut

さらにt/99_test_synopsis_expectation.tを作って以下のように書いてみます。

use strict;
use warnings;

use Test::More;
use Test::Synopsis::Expectation;

synopsis_ok('lib/AwesomeTarget.pm');

done_testing();

これで、なんと、

$ prove -l t/99_test_synopsis_expectation.t
t/99_test_synopsis_expectation.t .. ok
All tests successful.

テストが走ります。

SYNOPSISの# => 2を# => 1に変えてあげると

$ prove -l t/99_test_synopsis_expectation.t                                                                                                                                                [master]
t/99_test_synopsis_expectation.t .. 1/?
#   Failed test at /Users/mackee/.plenv/versions/5.16.3/lib/perl5/site_perl/5.16.3/Test/Synopsis/Expectation.pm line 48.
#          got: '2'
#     expected: '1'
# Looks like you failed 1 test of 1.

ちゃんとコケてくれます。こんなかんじでSYNOPSISを書いて、さらにそこにコメントを付け足すだけでテストを書くことが出来るめちゃお手軽テストモジュールです。

なんや!!! どうなっとるんや!!

そんな感じで、僕が作ったわけではないのですが少しだけ解説してみます。
このモジュール、id:moznionっていう人が作ったやつです。僕のじゃないです。

で、PODの解析部分なんですが、Compiler::Lexerが使われています。このモジュールはPerlのコードを構文解析するモジュールなのですが、perlの内部をいじくりまわしてどうこうしているわけではなく、トーカナイザなどが独自実装されています。PPIというPerlで実装されたPerl構文解析器もあるのですが、そちらよりも速いのが特徴です。
まずPod::Simple::Methodyを継承したモジュールでSYNOPSIS部分を抜き出し、そのコードをCompiler::Lexerに食わせてトーカナイズしてevalしてテスト出来る形まで持ってきています。
Test::Synopsis::Expectation自体は短いしやっていることは単純なのでCompiler::Lexerの一つのユースケースとして見てみると良いかと思われます。

そんな感じで、なんか夢がひろがりんぐなモジュールの紹介でした。あとでmoznionって人にビールをおごります。

さて、明日は……あれ、誰もいない? 何か書きたい人募集しています!!!!!

追記(12/17): moznionさんがもっと詳しい話を書いたので、もっと深く知りたい人はこちらへどうぞ!!!!!
Test::Synopsis::Expectationというモジュールをリリースしました - その手の平は尻もつかめるさ