FactoryGirl如何创建由回调关联创建的实例

时间:2016-05-31 06:35:54

标签: ruby-on-rails testing rspec factory-bot rspec-rails

考虑两种模式:

class User < ActiveRecord::Base

  has_one :book

  after_create :create_book
end

class Book < ActiveRecord::Base
  belongs_to :user

  validate_uniqueness :user_id
end

每个用户都可以拥有并且只能拥有一本书。然后我在我的规格中定义了两个工厂:

factory :user do
end

factory book do
  user
end

接下来是问题,当我为Book编写测试时,我想为book1创建记录Book(让我们称之为),当我使用{{ 1}}。它将创建FactoryGirl.create(:book)的实例,然后尝试创建定义的Book关联。创建用户后,系统会触发user,并为after_create创建book2。然后它尝试将userbook1绑定,并被唯一性关联阻止。

现在我正在使用user。这是最好的/正确的方法吗?我认为这很直观,因为我正在测试book = FactoryGirl.create(:user).book,我认为最好有Book

非常感谢。

1 个答案:

答案 0 :(得分:1)

我认为我们可以使用trait。这是一个例子:

<强>工厂

factory :user do
  # Your config here

  # Use trait
  trait :without_book do
    after(:build) do |user|
      allow(user).to receive(:create_book).and_return true
    end
  end

  trait :with_book do
    allow(user).to receive(:create_book).and_call_original
  end

  transient do
     # Use this by default but don't use this line also works
     # because we create book in the normal behavior
     with_book
  end
end

<强>规格

context 'test user without book' do
  let(:user) { FactoryGirl.create(:user, :without_book)

  it 'blah blah' do
  end
end

context 'test user with book' do
  let(:user) { FactoryGirl.create(:user, :with_book)
  # Or simply use this, because :with_book is default
  # let(:user) { FactoryGirl.create(:user)

  it 'blah blah' do
  end
end

顺便说一句,如你所见,我在allow(user).to receive(:create_book).and_return true使用了一个存根方法,基本上,这个实用工具方法来自rspec-mock,我们需要这个配置才能在工厂中使用它:

<强>规格/ rails_helper.rb

FactoryGirl::SyntaxRunner.class_eval do
  include RSpec::Mocks::ExampleMethods
end

理想情况下,您可以使用create为用户处理一本书not createtrait,模拟场景会更容易!