RSpec + FactoryGirl should_receive 失败
我不明白为什么这个 RSpec 测试失败。有什么建议吗?总的来说,我对 FactoryGirl、RSpec 和 TDD 还很陌生。
控制器:
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)>'
更新:
现在我更接近了。我将测试更改为以下内容:
it 'should update a given vendor' do
Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
do_update
end
新的错误是:
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)>'
答案...?
嗯,这有效。不过,必须有更好的方法来做到这一点:
Vendor.any_instance.should_receive(:update_attributes).with(JSON.parse(FactoryGirl.attributes_for(:vendor).to_json)).and_return(true)
I can't figure out why this RSpec test fails. Any advice? I'm new-ish to FactoryGirl, RSpec, and TDD in general.
Controller:
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
Test:
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
Factory:
FactoryGirl.define do
factory :vendor do
name 'Widget Vendor'
user
end
end
The Failure:
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)>'
Update:
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)>'
Answer...?
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为你做错了。
规范中的 @vendor 对象是控制器中的另一个对象,因此它不会接收“update_attributes”方法。
您可以尝试这个(可能是 rspec 2.5+):
或者您可以检查对象属性是否已更改:
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):
Or you can check if object attributes has changed:
我相信您需要在发布请求之前设定您的期望;否则,当它达到你的期望时,对象已经被设置了。因此,将
do_update
移到should_receive
行之后: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 yourshould_receive
line:您可以在rails中使用哈希字符串化键方法:
You can use the Hash stringify keys method in rails: