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

时间:2012-06-01 08:15:01

标签: 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

然后在我的测试中:

 create(:male)
 create(:female)
 create(:papas)
 create(:dumas)

请注意,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)

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

3 个答案:

答案 0 :(得分:14)

您可以通过不使用性别实例的工厂和在客户工厂中使用回调来实现您的目标。

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

Gender.find_or_create_by_code!('Male')

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

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

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

before(:create) do |customer|

而不是before_create

如果创建性别比您的示例更复杂,您仍然可以使用工厂创建性别,但使用find_by_code! find_or_create_by_code!的{​​{1}}内容使用回调将其与客户联系起来。

答案 1 :(得分:6)

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

相反,您可以使用transient attributes

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

答案 2 :(得分: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