例外を投げることを確認しつつ、値が変化することも確認したい
下記のようなクラスがあった時に、
StandardError
を投げることと、@num
の値が増えることを確認したい。
テスト対象のクラス
class TestTarget
attr_reader :num
def initialize
@num = 0
end
def call!
@num += 1
raise StandardError
end
end
マッチャーを繋げない書き方
raise_error
マッチャーで期待値を確認する前後の行で、値の変化を確認するとこうなる。
RSpec.describe 'TestTarget#call!' do
it '例外を投げ、@numの値が増える' do
t = TestTarget.new
# expect { t.call! }.to change(t, :num).by(1) のように書きたいけど、
# 例外が発生するから確認できない。
expect(t.num).to eq 0
expect { t.call! }.to raise_error(StandardError)
expect(t.num).to eq 1
end
end
マッチャーを繋げる書き方
マッチャーの戻り値に対してand
やor
メソッドを繋げることで、
raise_error
マッチャーの後ろにchange
マッチャーを繋げて書ける。
参考: https://relishapp.com/rspec/rspec-expectations/v/3-10/docs/compound-expectations
RSpec.describe 'TestTarget#call!' do
it '例外を投げ、@numの値が増える' do
t = TestTarget.new
# 引数渡しも、ブロック渡しも書ける。
expect { t.call! }.to raise_error(StandardError).and change(t, :num).by(1)
# or
expect { t.call! }.to raise_error(StandardError).and change { t.num }.by(1)
end
end
changeマッチャーの否定系(not)も確認したい場合
既存マッチャーの否定系を簡単に定義する機能を使って書ける。
参考: https://relishapp.com/rspec/rspec-expectations/v/3-10/docs/define-negated-matcher
RSpec.describe 'TestTarget#call!' do
before do
# changeマッチャーの否定系を定義
RSpec::Matchers.define_negated_matcher :not_change, :change
end
it '例外を投げ、@numの値が変化しない' do
t = TestTarget.new
# 引数渡しも、ブロック渡しも書ける。
expect { t.call! }.to raise_error(StandardError).and not_change(t, :num)
# or
expect { t.call! }.to raise_error(StandardError).and not_change { t.num }
end
end
最後に
※ @harashoo さんの記事も参考にさせていただきました。ありがとうございます。
※ RSpecのバージョン3.10.0で動作確認を行っています。