Question

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?

Was it helpful?

Solution

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:

  • one that tests that change_child_dummy_name is called (maybe it is not necessairy)
  • one that will test that the desired attributes of @child_dummy (because the object you create in your rspec test will not be the same that the method will return).
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top