Reputation: 3534
I can't figure out why this RSpec test fails. Any advice? I'm new-ish to FactoryGirl, RSpec, and TDD in general.
def update
@vendor = current_user.vendors.find(params[:id])
if @vendor.update_attributes(params[:vendor])
redirect_to vendor_path(@vendor)
else
render 'edit'
end
end
require 'spec_helper'
describe VendorsController do
login_user
before :each do
@user = subject.current_user
@vendor = FactoryGirl.create(:vendor, :user => @user)
end
[...]
describe 'POST update' do
def do_update
post :update, :id => @vendor.id, :vendor => FactoryGirl.attributes_for(:vendor)
end
[...]
it 'should update a given vendor' do
do_update
@vendor.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
end
end
end
FactoryGirl.define do
factory :vendor do
name 'Widget Vendor'
user
end
end
Failures:
1) VendorsController POST update should update a given vendor
Failure/Error: @vendor.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
(#<Vendor:0x007faeb75e77d0>).update_attributes({:name=>"Widget Vendor"})
expected: 1 time
received: 0 times
# ./spec/controllers/vendors_controller_spec.rb:108:in `block (3 levels) in <top (required)>'
I'm a little closer, now. I changed the test to the following:
it 'should update a given vendor' do
Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
do_update
end
And the new error is:
Failures:
1) VendorsController POST update should update a given vendor
Failure/Error: post :update, :id => @vendor.id, :vendor => FactoryGirl.attributes_for(:vendor)
#<Vendor:0x007ff30d765900> received :update_attributes with unexpected arguments
expected: ({:name=>"Widget Vendor"})
got: ({"name"=>"Widget Vendor"})
# ./app/controllers/vendors_controller.rb:33:in `update'
# ./spec/controllers/vendors_controller_spec.rb:98:in `do_update'
# ./spec/controllers/vendors_controller_spec.rb:108:in `block (3 levels) in <top (required)>'
Well, this worked. There has to be a better way of doing this, though:
Vendor.any_instance.should_receive(:update_attributes).with(JSON.parse(FactoryGirl.attributes_for(:vendor).to_json)).and_return(true)
Upvotes: 0
Views: 2533
Reputation: 1212
You can use the Hash stringify keys method in rails:
Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor).stringify_keys)
Upvotes: 0
Reputation: 7824
I think you are doing it wrong.
The @vendor object in specs is another one that in your controller, so it doesn't receive "update_attributes" method.
You can try this (rspec 2.5+ probably):
Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
Or you can check if object attributes has changed:
expect{
do_update
}.to change(...)
Upvotes: 2
Reputation: 124469
I believe you need to set your expectations before posting the request; otherwise, by the time it hits your expectation the object has already been set. So move do_update
after your should_receive
line:
it 'should update a given vendor' do
@vendor.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
do_update
end
Upvotes: 1