RSpec + FactoryGirl should_receive 失败

发布于 2024-12-15 23:59:54 字数 2552 浏览 2 评论 0原文

我不明白为什么这个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

泪是无色的血 2024-12-22 23:59:54

我认为你做错了。

规范中的 @vendor 对象是控制器中的另一个对象,因此它不会接收“update_attributes”方法。

您可以尝试这个(可能是 rspec 2.5+):

Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))

或者您可以检查对象属性是否已更改:

expect{
  do_update
}.to change(...)

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(...)
相权↑美人 2024-12-22 23:59:54

我相信您需要在发布请求之前设定您的期望;否则,当它达到你的期望时,对象已经被设置了。因此,将 do_update 移到 should_receive 行之后:

it 'should update a given vendor' do
  @vendor.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
  do_update
end

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
喜爱纠缠 2024-12-22 23:59:54

您可以在rails中使用哈希字符串化键方法:

Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor).stringify_keys)

You can use the Hash stringify keys method in rails:

Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor).stringify_keys)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文