RSpecのカスタムマッチャの作り方をいろいろ調べたのでメモ📝
作り方
RSpec::Matchers.define
を使う
カジュアルな追加方法としてRSpec::Matchers.define
で追加する方法があります。
以下の公式ドキュメントの通りにRSpec::Matchers.define
の引数にmatcher名を渡してdefineのブロック引数に期待する値、matchの引数に実際の値を指定してあげれば良いようです📝
You can create such a matcher like so:
RSpec::Matchers.define :be_in_zone do |zone| match do |player| player.in_zone?(zone) end end
Module: RSpec::Matchers — Documentation for rspec-expectations (3.12.3)
実際に以下のような単純に同一の値になるか確認するカスタムマッチャを追加して、
RSpec::Matchers.define :my_eq do |expected| match do |actual| expected == actual end end
以下のようなテストを流すと、
describe 'test' do it 'check my_eq' do expect(true).to my_eq(false) end end
以下のようにテスト結果が表示されます🙌
Failures: 1) test check my_eq Failure/Error: expect(true).to my_eq(false) expected true to my eq false
moduleで定義する
RSpec::Matchers.define
を使うとカジュアルに追加できますが実際にマッチャのテストコードを書きたいといった場合にはmoduleとして定義するとやりやすいようです。
以下のような検証用のロジックをもつclassとマッチャの呼び出すテストコード内で呼び出す名称のメソッドを持つmoduleを定義してあげて、
module MyEqMatcher class Matcher def initialize(expected) @expected = expected end def matches?(_expected) @actual = actual @expected == @actual end def failure_message "#{@expected} expected, but got #{@actual}" end end def my_eq(expected) Matcher.new(expected) end end
以下の通りにconfig.include
でテストコード内で利用できるようにすることができます。
RSpec.configure do |config| config.include MyEqMatcher end
以下の通り実行するといい感じにカスタムマッチャーを使ってエラーになることが確認できます 🙌
describe 'test' do it 'check my_eq' do expect(true).to my_eq(false) end end
1) test check my_eq Failure/Error: expect(true).to my_eq(false) false expected, but got true
おわりに
RSpecのカスタムマッチャ、意外と簡単に追加できて便利ですね!!