RSpec + FactoryGirl应该失败

时间:2011-11-16 16:51:09

标签: ruby-on-rails rspec2 factory-bot

我无法弄清楚为什么这个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)

3 个答案:

答案 0 :(得分:2)

我认为你做错了。

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

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

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

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

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

答案 1 :(得分:1)

我认为您需要在发布请求之前设定您的期望;否则,当它达到您的期望时,该对象已被设置。请在do_update行之后移动should_receive

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

答案 2 :(得分:0)

您可以在rails中使用Hash stringify键方法:

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