I have a problem with rspec behavior. I try to write test for service where I use session
, for read some value and overwrite this value.
For example what I want to test
class CurrentCartService
attr_reader :user, :session
def initialize(user, session)
@user = user
@session = session
end
def cart_id
{ id: session[:cart_id] }
end
def assigne_cart_to_session
session[:cart_id] = current_cart.id
end
spec
describe CurrentCartService do
let(:current_user) { user }
let(:session) { double('session') }
let!(:cart) { create(:cart) }
subject { described_class.new current_user, session }
before do
allow(session).to receive(:[]).and_return(cart.id)
end
describe '#call' do
context 'when user is not signed' do
let(:user) { nil }
it { subject.call }
end
end
end
binding.pry
session[:cart_id]
=> 574
session[:cart_id] = 123
RSpec::Mocks::MockExpectationError: #<InstanceDouble(session) (anonymous)> received unexpected message :[]= with (:cart_id, 123)
How to fix this? I tried to write some expect
expect(session).to receive(:[])
But it does not work, it's still the same error
The message is telling you that your double received the message []=
with arguments :cart_id
and 123
but didn't expect it.
Let's apply some basic logic. The problem is:
So, there are two things you can do to get rid of the message:
The first one is easy: just remove line 14 which says session[:cart_id] = current_cart.id
since that is the only place you are calling []=
. However, I don't think that is what you want to do.
Number two is also easy. There is a method called expect
which allows you to tell a double to expect a certain message. So, all we need to do, is to set up an expectation.
Good failure messages are really important in a testing framework, and thankfully, RSpec does have good failure messages. The failure message should tell you how to move forward with your tests, and the message you quoted contains all the information we need:
session
)[]=
):cart_id
and 123
)All we have to do is, without even thinking about it, literally just copy&paste this information:
expect(session).to receive(:[]=).with(:cart_id, 123)
Or, if we want our tests to be a little less brittle and not hard-code the 123
, we could also do something like this:
expect(session).to receive(:[]=).with(:cart_id, instance_of(Integer))