環境
- Rails 5.2.3
- rspec 3.8.2
やり方 その一
before
でallow(...).to receive(...)
して、
it
でexpect(...).to have_received(...)
する。
context 'when ...' do
before do
allow(Rails.logger).to receive(:error).with('error occurred')
end
it '...' do
do_something
expect(Rails.logger).to have_received(:error).with('error occurred').once
end
# 「呼ばれていないこと」を確認するためには、.to have_received を .not_to have_received にします。
it '...' do
do_something
expect(Rails.logger).not_to have_received(:error).with('error occurred')
end
end
controllerのmethodをmockする場合は、allow(controller).to receive(:some_method).and_return(true)
でOK。
やり方 その二
before
でexpect(...).to receive(...)
するだけでも動きます(期待動作します)。
しかし、rubocop-rspec
にRSpec/ExpectInHook: Do not use expect in before hook
(「before
ブロックでexpect
を使用するな」)
と怒られます。
context 'when ...' do
before do
expect(Rails.logger).to receive(:error).with('some message').once
end
end
なので it
の中で定義したほうが良さそうです。
context 'when ...' do
it do
expect(Rails.logger).to receive(:error).with('some message').once
do_something
end
end
しかし、↓のような感じで戻り値がある場合は、have_received
が使えないので、このやり方(before
に書くやり方)しかないように思うけど、何かいいやり方あるのかな?
before do
result = AuthenticateUser.call(token)
expect(AuthenticateUser).to receive(:call).with(token).and_return(result)
end
その他
以下のコードをモックする。
order = Order.by(customer).ordered_today.not_paid.order(created_at: :desc).first
if order&.purchased_but_not_paid?
@order = order
end
before do
order_class_double = class_double(Order)
order_instance_double = instance_double(Order, id: 1)
allow(Order).to receive(:by).and_return(order_class_double)
allow(order_class_double).to receive(:ordered_today).and_return(order_class_double)
allow(order_class_double).to receive(:not_paid).and_return(order_class_double)
allow(order_class_double).to receive(:order).and_return(order_class_double)
allow(order_class_double).to receive(:first).and_return(order_instance_double)
allow(order_instance_double).to receive(:purchased_but_not_paid?).and_return(true)
end