Perlでのテストメモ書き
なんとなくPerlの書きっぷりがわかってきたので、PerlでのUnitTestなど調べた。そのメモ。
基本的に Test::More ってのが Perl5.8 からついてくるので、これを使えばよさそう。RSpec 脳の人は Test::Spec とか使えばいいんじゃないかな?
Perlのプロジェクトの雛形を作らねばらんが、どんなディレクトリ構成が標準的なのかよくわからん。例によってググってみると、雛形を作成してくれるモジュールがいろいろあるらしい、最近できたっぽい、Module::Setup を使うことにした。使い方はここに書くより、適当に再度ググったらよかろう。
実際に書いてみるのが学習の早道なので、例によってTDD Boot Camp(TDDBC) - TDDBC大阪2.0/課題を借りる。
$ module-setup VendingMachine
と適当に作成。いろいろディレクトリが作成されるけど、そのうち勉強するということにして、lib と t の中身だけ気にすればいいでしょう。
とりあえず、テストケースの数をいちいち先頭に書くのは面倒なので t/00_compile.t を
use Test::More; BEGIN { use_ok 'VendingMachine' } done_testing;
な感じに修正する。とりあえず実行。
$ prove -l t t/00_compile.t .. ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU) Result: PASS
できた。これで終わってもいいけど、もう少し書こう。
Test::More は subtest によってテストを階層化できるみたいなので、どんどん利用する。フラットなテストケースって見難いよね。(似非)テストファーストで、貨幣を投入できる程度のテストをまず書く。
use strict; use warnings; use Test::More; use VendingMachine; subtest "貨幣が投入できる" => sub { subtest "初期状態(貨幣の投入なし)" => sub { my $vm = VendingMachine->new; is($vm->total, 0, "合計額はゼロ円"); $vm->back; is($vm->change, 0, "戻ってくるお釣りもゼロ円"); }; }; done_testing;
とりあえず、VendingMachine には new と total と back と change くらいが必要だよ、というテスト。
それっぽく、VendingMachine を実装。クラスの書き方とか適当にググっただけなので、おかしな書き方になってるかもしれんけど気にしない。
package VendingMachine; use strict; use warnings; our $VERSION = '0.01'; sub new { my $class = shift; my $self = { total => 0, change => 0, }; return bless $self, $class; } sub total { my $self = shift; return $self->{total}; } sub change { my $self = shift; return $self->{change}; } sub back { my $self = shift; $self->{change} = $self->total; $self->{total} = 0; } 1;
実行。
$ prove -l t t/00_compile.t .. ok t/01_money.t .... ok All tests successful. Files=2, Tests=2, 0 wallclock secs ( 0.03 usr 0.00 sys + 0.01 cusr 0.00 csys = 0.04 CPU) Result: PASS
通ったので、テストを追加する。
use strict; use warnings; use Test::More; use VendingMachine; subtest "貨幣が投入できる" => sub { subtest "初期状態(貨幣の投入なし)" => sub { my $vm = VendingMachine->new; is($vm->total, 0, "合計額はゼロ円"); $vm->back; is($vm->change, 0, "戻ってくるお釣りもゼロ円"); }; subtest "貨幣を投入する" => sub { my $vm = VendingMachine->new; $vm->put_in(100); $vm->put_in(50); is($vm->total, 150, "合計額が得られる"); $vm->back; is($vm->change, 150, "払い戻すと合計額が戻る"); is($vm->total, 0, "払い戻すと合計額がゼロになる"); }; }; done_testing;
貨幣を投入する put_in が必要になるので実装するよ。
... sub put_in { my ($self, $money) = @_; $self->{total} += $money; }
で、以下貨幣として許されない額が put_in に与えられた場合、などと続く。
冗長にテストを実行するとこんな感じ
$ prove -lv t/01_money.t t/01_money.t .. ok 1 - 合計額はゼロ円 ok 2 - 戻ってくるお釣りもゼロ円 1..2 ok 1 - 初期状態(貨幣の投入なし) ok 1 - 合計額が得られる ok 2 - 払い戻すと合計額が戻る ok 3 - 払い戻すと合計額がゼロになる 1..3 ok 2 - 貨幣を投入する 1..2 ok 1 - 貨幣が投入できる 1..1 ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.01 cusr 0.00 csys = 0.03 CPU) Result: PASS
表示が気にいらない人(つまり俺)は Test::Flatten とか使うといいよ。
$ prove -lv t/01_moeny.t t/01_money.t .. # ------------------------------------------------------------------------------ # 貨幣が投入できる # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # 初期状態(貨幣の投入なし) # ------------------------------------------------------------------------------ ok 1 - 合計額はゼロ円 ok 2 - 戻ってくるお釣りもゼロ円 # ------------------------------------------------------------------------------ # 貨幣を投入する # ------------------------------------------------------------------------------ ok 3 - 合計額が得られる ok 4 - 払い戻すと合計額が戻る ok 5 - 払い戻すと合計額がゼロになる 1..5 ok All tests successful. Files=1, Tests=5, 0 wallclock secs ( 0.01 usr 0.01 sys + 0.01 cusr 0.00 csys = 0.03 CPU) Result: PASS
まとめ
- Test::More でテスト書けるよ。
- Test::Flatten ナイス!
- before / after フックはない(多分)