I've got a few tests like this:
it 'should invite user again' do
admin_user = create(:invited_admin_user)
expect_any_instance_of(AdminUser).to receive(:invite!).and_return(true)
patch :reinvite, params: { id: admin_user.to_param }
end
I really want to write it like this:
it 'should invite user again' do
admin_user = create(:invited_admin_user)
expect(admin_user).to receive(:invite!).and_return(true)
patch :reinvite, params: { id: admin_user.to_param }
end
But the test fails if I do that. Any idea why that would happen? I'm using factory_bot to create the AdminUser instance.
I've tried putting puts statements in the test and the invite method to confirm the ID.
def invite!(_param1 = AdminUser.new, _param2 = {})
puts 'ID in invite!' + self.id.inspect
super(_param1, _param2)
end
it 'should invite user again' do
admin_user = create(:invited_admin_user)
puts 'adminuser created' + admin_user.id.inspect
expect(admin_user).to receive(:invite!).and_return(true)
patch :reinvite, params: { id: admin_user.to_param }
end
Result
adminuser created7768
ID in invite!7768
Why do you want to use mocks here in the first place?
it 'should invite user again' do
admin_user = create(:invited_admin_user)
patch :reinvite, params: { id: admin_user.to_param }
expect(admin_user.reload.invited).to eq(true)
end
If you want to avoid redundant calls to the database, the whole test should be written a) without a real DB object creation (FactoryGirl#build
,) b) without patch
call (directly call the respective controller’s method,) and c) mocking everything to be called in between.
NB I personally do not see any reason at all to have tests where everything is mocked: they hardly differ from the code itself. I mean, we could make a mistake in the test as well as in the code and checking that patch
calls the respective controller’s method is silly: it’s already checked in Rails tests. I always try to test real things, when applicable (like the user was indeed changed, rather than some method was invoked.)