Factory Девушка создает связь с существующим объектом

Я новичок в 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_id - nil.

Если я удалю связь :strategy => :build с Customer :papas factory с полом, то я получу ошибку, что при попытке создать :papas код для пола уже существует.

Что мне нужно сделать, чтобы мои тесты создавали данные, как указано выше?

Обратите внимание, что я хочу, чтобы гендерные группы были созданы без клиентов, а также в других тестах. Не говорите мне, чтобы создавать клиентов с помощью factory создавать команды и позволять клиентам создавать гендерные группы одновременно. Это не сработает, если я попытаюсь создать двух клиентов того же пола.

Кроме того, должен быть лучший ответ, чем тот:

@male = create(:male)
@female = create(:female)
create(:papas, :gender => @male)
create(:dumas, :gender => @female)

(При использовании приспособлений эти вещи были готовы из коробки. Должен ли я вернуться к светильникам?)

Ответ 1

Вы можете достичь того, чего хотите, не используя factory для своих экземпляров Gender и используя обратные вызовы в вашем клиенте factory.

Вы не получаете много от Гендерного factory в его нынешнем виде (хотя я ценю, что это может быть упрощено с целью задать этот вопрос). Вы можете так же легко сделать это, чтобы получить пол:

Gender.find_or_create_by_code!('Male')

Затем в вашем Customer factory вы можете использовать перед обратным вызовом, чтобы установить пол:

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.

Если создание пола более сложно, чем ваш пример, вы все равно можете создать гендерные группы с помощью factory, но подключите их к своим клиентам с помощью обратных вызовов с помощью find_by_code! insteand find_or_create_by_code!.

Ответ 2

Блок 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

Ответ 3

ignore устарел и будет удален на версии 5 из Factory Girl.

Вместо этого вы можете использовать переходные атрибуты:

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