Test::Spec入門
元ネタ「RSpec の入門とその一歩先へ - t-wadaの日記」第一イテレーション。
PerlのTest::Specだとどうなるかやってみた。
message_filter_spec.t
t/message_filter_spec.t
+use Test::Spec; # use strict/warningsもされるらしい。へぇ + +describe MessageFilter => sub { +}; + +runtests unless caller;
- 実行してみる
$ perl t/message_filter_spec.t no examples defined in spec package main at /Users/rightgo09/.perl5/perls/perl-5.16.2/lib/site_perl/5.16.2/Test/Spec/Context.pm line 273. 1..0 # No tests run!
- RSpecでは「MessageFilterが見つからない」というエラーなのに対してTest::Specでは「実行するテストがない」というエラーになった
MessageFilter.pmを作成する
lib/MessageFilter.pm
+package MessageFilter { + use strict; + use warnings; +} + +1;
t/message_filter_spec.t
+use MessageFilter; use Test::Spec; describe MessageFilter => sub { }; runtests unless caller;
- 実行してみる
$ perl -Ilib t/message_filter_spec.t no examples defined in spec package main at /Users/rightgo09/.perl5/perls/perl-5.16.2/lib/site_perl/5.16.2/Test/Spec/Context.pm line 273. 1..0 # No tests run!
- まだ同じ
最初のテストを書く
t/message_filter_spec.t
use MessageFilter; use Test::Spec; describe MessageFilter => sub { + it 'should detect message with NG word' => sub { + my $filter = MessageFilter->new('foo'); + ok($filter->is_detect('hello from foo')); + }; }; runtests unless caller;
- shouldがないのが残念
- あとPerlはメソッド名に「?」が使えない代わりに、booleanはis_xxxxがよく使われる
- 実行してみる
$ perl -Ilib t/message_filter_spec.t not ok 1 - MessageFilter should detect message with NG word # Failed test 'MessageFilter should detect message with NG word' by dying: # Can't locate object method "new" via package "MessageFilter" # at t/message_filter_spec.t line 6. 1..1 # Looks like you failed 1 test of 1.
- 「newがありません」というエラー。さすがPerl。
コンストラクタ作成
lib/MessageFilter.pm
package MessageFilter { use strict; use warnings; + + sub new { + my ($class, $word) = @_; + bless { word => $word }, $class; + } } 1;
- 実行してみる
$ perl -Ilib t/message_filter_spec.t not ok 1 - MessageFilter should detect message with NG word # Failed test 'MessageFilter should detect message with NG word' by dying: # Can't locate object method "is_detect" via package "MessageFilter" # at t/message_filter_spec.t line 7. 1..1 # Looks like you failed 1 test of 1.
- 「is_detectがない」と怒られる
is_detectメソッド作成
- 空のメソッドを作る
lib/MessageFilter.pm
package MessageFilter { use strict; use warnings; sub new { my ($class, $word) = @_; bless { word => $word }, $class; } + + sub is_detect { + } } 1;
- 実行してみる
$ perl -Ilib t/message_filter_spec.t not ok 1 - MessageFilter should detect message with NG word # Failed test 'MessageFilter should detect message with NG word' # at t/message_filter_spec.t line 7. 1..1
- 「Failed test」だけだけど、ok()使っているだけなので、trueでない値が返ってきたようである
仮実装
lib/MessageFilter.pm
package MessageFilter { use strict; use warnings; sub new { my ($class, $word) = @_; bless { word => $word }, $class; } sub is_detect { + return 1; } } 1;
- 一番trueだと分かりやすい1を返すようにする
- 実行してみる
$ perl -Ilib t/message_filter_spec.t ok 1 - MessageFilter should detect message with NG word 1..1
- 通った! やったね!
三角測量
- テストを増やす
t/message_filter_spec.t
use MessageFilter; use Test::Spec; describe MessageFilter => sub { it 'should detect message with NG word' => sub { my $filter = MessageFilter->new('foo'); ok($filter->is_detect('hello from foo')); }; + it 'should not detect message without NG word' => sub { + my $filter = MessageFilter->new('foo'); + ok(!$filter->is_detect('hello, world')); + }; }; runtests unless caller;
- 実行してみる
$ perl -Ilib t/message_filter_spec.t ok 1 - MessageFilter should detect message with NG word not ok 2 - MessageFilter should not detect message without NG word # Failed test 'MessageFilter should not detect message without NG word' # at t/message_filter_spec.t line 11. 1..2 # Looks like you failed 1 test of 2.
- いい感じに失敗した
明白な実装
- MessageFilter.pmに実装する
lib/MessageFilter.pm
package MessageFilter { use strict; use warnings; sub new { my ($class, $word) = @_; bless { word => $word }, $class; } sub is_detect { - return 1; + my ($self, $word) = @_; + return index($word, $self->{word}) >= 0; } } 1;
- 実行してみる
$ perl -Ilib t/message_filter_spec.t ok 1 - MessageFilter should detect message with NG word ok 2 - MessageFilter should not detect message without NG word 1..2
- OK
テストのリファクタリング
beforeメソッドの抽出
- before部分に毎回のfilterインスタンス作成をくくりだす
t/message_filter_spec.t
use MessageFilter; use Test::Spec; describe MessageFilter => sub { + my $filter; + before each => sub { + $filter = MessageFilter->new('foo'); + }; + it 'should detect message with NG word' => sub { - my $filter = MessageFilter->new('foo'); ok($filter->is_detect('hello from foo')); }; it 'should not detect message without NG word' => sub { - my $filter = MessageFilter->new('foo'); ok(!$filter->is_detect('hello, world')); }; }; runtests unless caller;
- 変数スコープの関係上、beforeとitの外側で$filterを宣言しておく必要がある
- あとはRSpecと同じでitの直前にbeforeが実行される
- 実行してみる
$ perl -Ilib t/message_filter_spec.t ok 1 - MessageFilter should detect message with NG word ok 2 - MessageFilter should not detect message without NG word 1..2
eachは不要
- Test::SpecもRSpecと当然同じ理念なので、beforeのデフォルトはeachである
t/message_filter_spec.t
use MessageFilter; use Test::Spec; describe MessageFilter => sub { my $filter; - before each => sub { + before sub { $filter = MessageFilter->new('foo'); }; it 'should detect message with NG word' => sub { ok($filter->is_detect('hello from foo')); }; it 'should not detect message without NG word' => sub { ok(!$filter->is_detect('hello, world')); }; }; runtests unless caller;
- 実行してみる
$ perl -Ilib t/message_filter_spec.t ok 1 - MessageFilter should detect message with NG word ok 2 - MessageFilter should not detect message without NG word 1..2
be_[predicate]マッチャ
- そんなものはなーい
メッセージ
- Test::Moreだと自力で最後の引数にテスト用のメッセージを書く必要があるけれど、Test::Specだと自動でいい感じに出してくれてる!