Factory Girl创建与现有对象的关联

p.m*_*los 11 ruby-on-rails associations factory-bot

我是FactoryGirl的新手,我正在尝试以下简单方案?

factory :female, :class => Gender do
  code 'Female'
end

factory :male, :class => Gender do
  code 'Male'
end

factory :papas, :class => Customer do
  first_name 'Jim'
  last_name 'Papas'
  association :gender, :factory => :male, :strategy => :build
end

factory :dumas, :class => Customer do
  first_name 'Mary'
  last_name 'Dumas'
  association :gender, :factory => :female, :strategy => :build
end
Run Code Online (Sandbox Code Playgroud)

然后在我的测试中:

 create(:male)
 create(:female)
 create(:papas)
 create(:dumas)
Run Code Online (Sandbox Code Playgroud)

请注意,Customer类具有关联belongs_to Gender类和验证规则,该规则gender_id应该存在.我还对Gender类的唯一性进行了验证.

create(:papas)上面的声明中,在我的测试中,我得到了Customer将要创建的错误无效的错误,因为gender_idnil.

如果删除了:strategy => :build关于Customer :papas性别工厂协会的话,我会得到一个错误,即试图创建时:papas,为性别代码已经存在.

我需要做什么才能使测试按上述要求创建数据?

请注意,在其他测试中,我希望在没有客户的情况下创建性别.不要告诉我使用工厂创建命令创建客户,让客户同时创建性别.如果我尝试创建两个性别相同的客户,这将无效.

此外,必须有一个比一个更好的答案:

@male = create(:male)
@female = create(:female)
create(:papas, :gender => @male)
create(:dumas, :gender => @female)
Run Code Online (Sandbox Code Playgroud)

(当使用固定装置时,这些东西已经开箱即用.我应该回到固定装置吗?)

Sha*_*ell 14

您可以通过不使用性别实例的工厂和在Customer工厂中使用回调来实现您的需求.

你现在没有从性别工厂中获得很多收益(尽管我很欣赏它可能会被简化以便提出这个问题).您可以轻松地这样做以获得性别:

Gender.find_or_create_by_code!('Male')
Run Code Online (Sandbox Code Playgroud)

然后在您的客户工厂中,您可以使用之前的回调来设置性别:

factory :dumas, :class => Customer do
  first_name 'Mary'
  last_name 'Dumas'
  before_create do |customer|
    customer.gender = Gender.find_or_create_by_code!('Female')
  end
end
Run Code Online (Sandbox Code Playgroud)

在factory_girl中使用回调的格式最近已经改变,所以如果你使用3.3或更高版本,你需要这样做:

before(:create) do |customer|
Run Code Online (Sandbox Code Playgroud)

而不是before_create.

如果创建一个性别比你的例子更复杂,你仍然可以使用工厂创建性别,但使用find_by_code!insteand 使用回调将它们与客户联系起来find_or_create_by_code!.


Kos*_*sis 6

ignore 已被弃用,将在Factory Girl的第5版中删除.

相反,您可以使用瞬态属性:

factory :dumas, :class => Customer do
  transient do
    female { Gender.find_by_code('Female') || create(:female) }
  end

  first_name 'Mary'
  last_name 'Dumas'
  gender { female }
end
Run Code Online (Sandbox Code Playgroud)


Dav*_*ton 5

ignore块也可用于包装它:

factory :dumas, :class => Customer do
  ignore do
    female { Gender.find_by_code('Female') || create(:female) }
  end

  first_name 'Mary'
  last_name 'Dumas'
  gender { female }
end
Run Code Online (Sandbox Code Playgroud)