yekta
yekta

Reputation: 3433

Rails / AR – how to test ::update(id, attributes) in rspec

I'm using the active record update method to update multiple records, each with their own individual attributes.

I facilitate that with this controller code (which works):

def update
  keys = params[:schedules].keys
  values = params[:schedules].values
  if Schedule.update(keys, values)
    flash[:notice] = "Schedules were successfully updated."
  else
    flash[:error] = "Unable to update some schedules."
  end
  respond_to do |format|
    format.html { redirect_to responsibilities_path }
  end
end

My question is, how can I test that without hitting the database in rspec?

Here's what I'm trying, but its not working.

describe "PATCH update" do

  it "updates the passed in responsibilities" do
    allow(Schedule)
      .to receive(:update)
      .with(["1", "2"], [{"status"=>"2"}, {"status"=>"1"}])
      .and_return(true)
    # results in
    # expected: 1 time with arguments: (["1", "2"], [{"status"=>"2"}, {"status"=>"1"}])
    # received: 0 times
    # Couldn't find Schedule with 'id'=1

    # without the allow, I get
    # Failure/Error: patch :update, schedules: {
    # ActiveRecord::RecordNotFound:
    #   Couldn't find Schedule with 'id'=1
    # # ./app/controllers/responsibilities_controller.rb:18:in `update'
    # # ./lib/authenticated_system.rb:75:in `catch_unauthorized'
    # # ./spec/controllers/responsibilities_controller_spec.rb:59:in `block (5 levels) in <top (required)>'

    patch :update, schedules: {
      "1" => {
        "status" => "2",
      },
      "2" => {
        "status" => "1",
      }
    }
    expect(Schedule)
      .to receive(:update)
      .with(["1", "2"], [{"status"=>"2"}, {"status"=>"1"}])
    expect(flash[:error]).to eq(nil)
    expect(flash[:notice]).not_to eq(nil)
  end
end

I'm on Rails 4.2.4 and rspec 3.0.0

Upvotes: 1

Views: 659

Answers (1)

jfornoff
jfornoff

Reputation: 1368

your problem is, that you are expecting with

expect(Schedule)
      .to receive(:update)
      .with(["1", "2"], [{"status"=>"2"}, {"status"=>"1"}])
      .and_call_original     

after calling the patch method.

That means the request hits your controller before the assertion is established. To solve that, just put the expect(Schedule) call before the patch call, that also allows you to get rid of the allow(Schedule).to - call.

Cheers.

Upvotes: 2

Related Questions