Eric Baldwin
Eric Baldwin

Reputation: 3501

Using rspec to confirm a function is called within a controller

I am trying to confirm a function was called in a controller method with an rspec test. To do this, I'm following the relishapp documentation for confirming an instance of a class receives a message. My implementation is as follows:However, I keep getting the following error:

  it "does the job" do
    expect {
      post :create, {:obj => valid_attributes}
    }.to change(Object, :count).by(1)
    Object.any_instance.should_receive(:delay)
    flash[:notice].should eq(I18n.t(:success, obj: 'object', past_participle: 'created'))
    response.should redirect_to(new_object_path)
  end

However, I keep getting the following error:

Failure/Error: Unable to find matching line from backtrace
   Exactly one instance should have received the following message(s) but didn't: delay

In this case, I'm trying to confirm the delay method was called. I can clearly see the method is called in the controller method, why doesn't rspec confirm it?

Upvotes: 1

Views: 1186

Answers (1)

Hari Gopal
Hari Gopal

Reputation: 718

As I see it, there are two ways to approach testing this behavior.

You could ignore the delaying of cio_register() method when testing, as Delayed Job documentation suggests, with Delayed::Worker.delay_jobs = false. I believe this is because we can safely assume that Delayed Job will work.

I would re-write the tests as follows:

describe '#create'
  it 'creates a new Object' do
    expect {
      post :create, {:object => valid_attributes}
    }.to change(Object, :count).by(1)
  end

  it 'performs CIO registration on new object' do
    # Skip Delayed Jobs.
    original_setting = Delayed::Worker.delay_jobs
    Delayed::Worker.delay_jobs = false

    # Our expectation.
    Object.any_instance.should_receive(:cio_register)

    post :create, {:object => valid_attributes}

    # Restore Delayed Job's setting.
    Delayed::Worker.delay_jobs = original_setting
  end

  it 'sets appropriate flash message'
  it 'redirects to path showing details of newly created Object'
end

If the delaying is critical to the behavior of the method, you could work the job in the test and ensure its result:

it 'performs CIO registration on new object' do
  # Our expectation.
  Object.any_instance.should_receive(:cio_register)

  post :create, {:object => valid_attributes}

  # Let's process the delayed job.
  Delayed::Worker.new.work_off
end

I found this interesting entry while googling: http://artsy.github.io/blog/2012/08/16/testing-with-delayed-jobs/

Upvotes: 1

Related Questions