概要
rspecでテストを書いていると、値だけ違う同じexpectの組み合わせを何度も行うことが多いと思います。仕様が変わったりすると大量に変更箇所が出てきて、「あ〜やっぱりテストはコストがかかるからやめようか〜」なんてことになりかねません。ヘルパーメソッド的なものにまとめたいと思いました。
で、どこにexpectをまとめたヘルパーメソッドを作るのか探してみると、カスタムマッチャーを使った例がいくつか見つかりました。
ところがカスタムマッチャーのmatchメソッドはtrue/falseを返すように設計されているため、なかでexpectを使うとエラーメッセージがもみ消されて、どこで、どんな感じにテストがこけたのか全く分からなくなってしまいます。
また、追加的なテストはchainメソッドで行いますが、これはテストを実行するというより、メンバー変数に値を入れておき、matchメソッドの中でその変数の有無を見て追加チェックを行うためロジックが複雑になってしまいます。
そこで、いい感じにテストをまとめられるmoduleを作りましたので共有させていただきます。エラーメッセージの問題はこちらの投稿を参考にしました。
モジュールはgistに公開しました。
https://gist.github.com/gomo/83e021828a0aeade3b3370d404c2ee7b
使い方
RSpec::Matchers.define
のブロックにincludeして使います。
RSpec::Matchers.define :have_foo_bar do |foo, bar|
include ChainChecker
エントリーポイントはmatch
ではなくmain
に渡すブロックになります。
RSpec::Matchers.define :have_foo_bar do |foo, bar|
include ChainChecker
main do |actual|
expect(actual.foo).to eq foo
expect(actual.bar).to eq bar
# メンバー変数に入れて置くとchainの中で利用可能です。
@quux = actual.quux
end
chain
メソッドではcheck
メソッドにブロックを渡してテストを予約します。これでmainに渡したブロックが最初に評価され、その後chainを呼び出した順にcheckブロックが評価されていきます。
RSpec::Matchers.define :have_foo_bar do |foo, bar|
include ChainChecker
main do |actual|
expect(actual.foo).to eq foo
expect(actual.bar).to eq bar
@quux = actual.quux
end
chain :with_quux do |baz, qux|
check do |actual|
expect(@quux.baz).to eq baz
expect(@quux.qux).to eq qux
end
end
end
テストコードは下記のようになります。
context 'some' do
it 'should have foo and bar' do
some = Some.find(1)
expect(some).to have_foo_bar('foo value', 'bar value')
.with_quux('baz value', 'qux value')
end
end