2012-06-01 3 views
10

Je suis nouveau à FactoryGirl et j'essaie le scénario simple suivant?Factory Girl créer une association avec l'objet existant

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 

Puis dans mon test:

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

Notez que la classe client a une classe et une règle de validation assocation belongs_toGender qui dit que gender_id devrait être présent. J'ai également une validation sur Gender classe pour l'unicité sur le code.

Sur create(:papas) déclaration ci-dessus, dans mon test, je reçois l'erreur que le Customer qui va être créé est pas valide, parce que gender_id est nil.

Si je supprime le :strategy => :build sur Customer:papas association d'usine avec le sexe, alors je vais faire une erreur, que lorsque vous essayez de créer :papas, le code pour le sexe existe déjà.

Que dois-je faire pour que mes tests créent les données comme requis ci-dessus?

Notez que je veux avoir des genres créés sans clients aussi, dans d'autres tests. Ne me dites pas de créer les clients avec des commandes de création d'usine et laissez les clients créer les genres en même temps. Cela ne fonctionnera pas si j'essaye de créer deux clients du même sexe aussi.

En outre, il doit y avoir une meilleure réponse que celle:

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

(.? Lors de l'utilisation des appareils de ces choses étaient prêts hors-the-box Dois-je retourner à fixtures)

Répondre

14

Vous pouvez réaliser ce que vous voulez en n'utilisant pas d'usine pour vos instances de genre et en utilisant des rappels dans votre usine du client.

Vous ne gagnez pas grand-chose de l'usine de genre en l'état (bien que j'apprécie qu'il puisse être simplifié pour poser cette question). Vous pourriez tout aussi bien le faire pour obtenir un Sexe:

Gender.find_or_create_by_code!('Male') 

Ensuite, dans votre usine de client, vous pouvez utiliser un avant rappel pour définir le genre:

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 

Le format pour l'utilisation callbacks dans factory_girl a a récemment changé si vous utilisez 3.3 ou plus tard, vous devrez faire:

before(:create) do |customer| 

au lieu de before_create.

Si la création d'un sexe est plus complexe que votre exemple, vous pouvez toujours créer les sexes en utilisant une usine, mais les connecter avec vos clients en utilisant les rappels en utilisant find_by_code! et find_or_create_by_code!.

+0

Bien que très bavard vs fixtures, votre réponse est correcte. J'ai utilisé usine fille les deux derniers mois et encore mon prochain projet sera avec des appareils! –

+1

L'avantage que vous pourriez trouver avec les usines est si vous avez besoin de créer beaucoup de clients différents. Vous pouvez avoir une usine male_customer et female_customer et les utiliser comme usines parentales pour vos différents clients - cela réduit considérablement la verbosité. Heureux que ça a marché! – Shadwell

5

Le bloc ignore peut être utilisé pour envelopper cette place ainsi:

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 
5

ignore a été désapprouvée et sera supprimée de la version 5 de Factory Girl.

Au lieu de cela, vous pouvez utiliser 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 
Questions connexes