Let's say I have a dummy presenter class for my dummy model like this:
class DummyPresenter
def initialize(dummy_id)
@dummy = DummyModel.find(dummy_id)
end
def id
@dummy.id
end
def change_child_dummy_name(child_dummy_id, new_child_dummy_name)
child_dummy = @dummy.child_dummies.find(child_dummy_id)
child_dummy.update_attributes(:display_name => new_child_dummy_name)
child_dummy # I need to return a child_dummy object here!!
end
end
In my spec:
require 'spec_helper'
describe DummyPresenter do
before :all do
@dummy_presenter = DummyPresenter.new(1)
@child_dummy = DummyModel.find(1).child_dummies.first
end
it 'should update the display name of a child dummy for a dummy' do
expect(@child_dummy.display_name).to be_nil
@dummy_presenter.change_child_dummy_name(@child_dummy.id, 'Child Dummy network')
@child_dummy.reload
expect(@child_dummy.display_name).to eq('Child Dummy network')
end
it 'should return updated child dummy' do
child_dummy_id = @child_dummy.id
@dummy_presenter.should_receive(:change_child_dummy_name).at_least(:once).with(child_dummy_id, 'Child Dummy network').and_return(@child_dummy)
@dummy_presenter.change_child_dummy_name(child_dummy_id, 'Child Dummy network')
end
end
Above test cases pass without any issue.
Now, as per my understanding the first it
block works perfectly fine where I just see the updated attribute. But, the second block where I expect the method: change_child_dummy_name
to return @child_dummy
doesn't work or maybe I didn't understand the code I've written here properly. Because, when I change change_child_dummy_name
method inside presenter to this:
def change_child_dummy_name(child_dummy_id, new_child_dummy_name)
child_dummy = @dummy.child_dummies.find(child_dummy_id)
child_dummy.update_attributes(:display_name => new_child_dummy_name)
"child_dummy" # A String!! Where as I need to return a child_dummy object here!!
end
The specs again pass without raising any error. So, what am I doing wrong?
If I am not mistaken, the essence of this question is here
@dummy_presenter.should_receive(:change_child_dummy_name).at_least(:once).with(child_dummy_id, 'Child Dummy network').and_return(@child_dummy)
should_receive
actually stubs the method's result.
if and_returns
is used, its operand is the new value, if not the stubbed value is nil
.
In your case that is the @child_dummy
object. Which by the way is the reason your test passed the first time as well!
One way to bypass this behavior is to use .and_call_original
which will do what you expect.
You should rewrite it as two tests:
change_child_dummy_name
is called (maybe it is not necessairy)@child_dummy
(because the object you create in your rspec test will not be the same that the method will return).