Test::Specその3
they
- 単なるitのエイリアス
- 複数形の言い回しに向いてる
xdescribe/xcontext/xit/xthey
- それぞれdescribe/context/itの代わりに使う
- 要はpending扱いにしてくれる
- TODOラベルを貼る必要がない
spec_helper
- 各テストファイルで共通のものを書いておいて、spec_helperでそのファイルを各テストファイルから呼び出す
- shared_examples_for も置ける
- ただし変数スコープは存在するので、共有にはshareを使わないといけない
- use strict/warningsしなくても、その恩恵には与れる
share
- 同じテストファイル内で変数を受け渡すなら、そのファイル内のトップレベルに変数を宣言すればいいけれど、各テストで共有したいときにshareを使う
- spec_helper.plに使うのが便利そう
- 使用範囲がそのブロックに収束するなら、myも一緒に宣言
- 変数名は別になんでもいい
- 要するにtie
- っていうか実装もtieされてるだけだった
その2までやってた分をspec_helper.plに分けてみた。
lib/MessageFilter.pm
package MessageFilter { use strict; use warnings; sub new { my ($class, @ng_words) = @_; bless { ng_words => \@ng_words }, $class; } sub ng_words { my $self = shift; return @{$self->{ng_words}}; } sub is_detect { my ($self, $word) = @_; return grep index($word, $_) >= 0, $self->ng_words; } } 1;
t/spec_helper.pl
# use warningsされるかテスト undef == 1; shared_examples_for 'MessageFilter with argument "foo"' => sub { share my %vars; # shareで共有 it 'should detect message with NG word' => sub { ok($vars{filter}->is_detect('hello from foo')); }; it 'should not detect message without NG word' => sub { ok(!$vars{filter}->is_detect('hello, world')); }; it 'ng_words should not be empty' => sub { ok($vars{filter}->ng_words); }; };
t/message_filter_spec.t
use MessageFilter; use Test::Spec; # 外部ファイル読み込み spec_helper 'spec_helper.pl'; describe MessageFilter => sub { share my %vars; # shareで共有 my $filter; context 'with argument "foo"' => sub { before sub { # share変数にも入れておく $vars{filter} = $filter = MessageFilter->new('foo'); }; it_should_behave_like 'MessageFilter with argument "foo"'; it 'ng_words size is 1' => sub { cmp_ok(scalar($filter->ng_words), '==', 1); }; }; context 'with argument "foo","bar"' => sub { before sub { # share変数にも入れておく $vars{filter} = $filter = MessageFilter->new('foo', 'bar'); }; it 'should detect message with NG word' => sub { ok($filter->is_detect('hello from bar')); }; it_should_behave_like 'MessageFilter with argument "foo"'; it 'ng_words size is 2' => sub { cmp_ok(scalar($filter->ng_words), '==', 2); }; }; # pending xcontext 'with argument qr/foo/' => sub { before sub { $filter = MessageFilter->new(qr/foo/); }; xit 'should detect message with NG word' => sub { ok($filter->is_detect('hello from foo')); }; }; }; runtests unless caller;
$ perl -Ilib t/message_filter_spec.t Useless use of numeric eq (==) in void context at spec_helper.pl line 1, <> line 1. Use of uninitialized value in numeric eq (==) at spec_helper.pl line 1, <> line 1. ok 1 - MessageFilter with argument "foo" ng_words size is 1 ok 2 - MessageFilter with argument "foo" should detect message with NG word ok 3 - MessageFilter with argument "foo" should not detect message without NG word ok 4 - MessageFilter with argument "foo" ng_words should not be empty ok 5 - MessageFilter with argument "foo","bar" should detect message with NG word ok 6 - MessageFilter with argument "foo","bar" ng_words size is 2 ok 7 - MessageFilter with argument "foo","bar" should detect message with NG word ok 8 - MessageFilter with argument "foo","bar" should not detect message without NG word ok 9 - MessageFilter with argument "foo","bar" ng_words should not be empty ok 10 - MessageFilter with argument qr/foo/ should detect message with NG word # TODO (disabled) 1..10
Test::Spec::Mocks
- RubyのMochaからインスパイアされたものらしい
# インスタンスメソッド # doメソッドを呼び出されたら、無条件で1を返す $dbh->stubs(do => sub { $sql = shift; return 1 }); $dbh->do('SET NAMES utf8'); #=> 1 # クラスメソッドでもOK DateTime->stubs('now' => sub { DateTime->new(from_epoch => 0xdeafcab) });