考虑两种模型:
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
, 当我使用 FactoryGirl.create(:book)
.它将创建 Book
的实例然后尝试创建关联定义 user
.创建用户后,after_create
是触发器,book2
为 user
创建.然后它尝试绑定(bind) book1
与 user
并被唯一性关联阻止。
现在我正在使用 book = FactoryGirl.create(:user).book
.这是最好/正确的方法吗?我认为它很直观,因为我正在测试 Book
, 我认为最好有 book = FactoryGirl.create(:book)
非常感谢。
最佳答案
我认为我们可以为此使用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
处使用了一个 stub 方法,基本上,这个实用方法来自 rspec-mock
,我们需要此配置以使其在工厂中可用:
spec/rails_helper.rb
FactoryGirl::SyntaxRunner.class_eval do
include RSpec::Mocks::ExampleMethods
end
理想情况下,您可以通过为用户使用trait
来处理创建
或不创建
一本书,这样会更容易模拟场景!
关于ruby-on-rails - FactoryGirl 如何创建一个由关联回调创建的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37538451/