Faker produit des données en double lorsqu'il est utilisé dans factory_girl

86

J'essaie de remplir de fausses données dans une usine à l'aide du gem Faker:

Factory.define :user do |user|
  user.first_name Faker::Name::first_name
  user.last_name Faker::Name::last_name
  user.sequence(:email) {|n| "user#{n}@blow.com" }
end

Cependant, même si je m'attends à ce que cela produise des utilisateurs qui ont des prénoms et des noms de famille différents, chacun est le même:

>> Factory(:user)
=> #<User id: 16, email: "[email protected]", created_at: "2011-03-18 18:29:33",     
updated_at: "2011-03-18 18:29:33", first_name: "Bailey", last_name: "Durgan">
>> Factory(:user)
=> #<User id: 17, email: "[email protected]", created_at: "2011-03-18 18:29:39", 
updated_at: "2011-03-18 18:29:39", first_name: "Bailey", last_name: "Durgan">

Comment puis-je faire en sorte que la gemme Faker génère de nouveaux noms pour chaque utilisateur et pas seulement réutiliser les originaux?

Peter Nixey
la source
1
Juste une photo dans le noir, mais avez-vous essayé d'utiliser quelque chose comme user.sequence(:first_name} {|n| Faker::Name::first_name}? FactoryGirl évalue probablement simplement votre appel Faker quand il charge vos "projecteurs". L'utilisation de la sequence param,&blockméthode devrait empêcher cela.
Steven

Réponses:

156
Factory.define :user do |user|
  user.first_name { Faker::Name::first_name }
  user.last_name { Faker::Name::last_name }
  user.sequence(:email) {|n| "user#{n}@blow.com" }
end

Essayez de mettre des crochets autour des faux. voir ce lien

Will Ayd
la source
8
J'aime tellement stackoverflow - merci Will, vous avez sauvé mon bacon
Peter Nixey
Merci, cela a résolu mon problème!
Oranges13
5
Pourquoi, pourquoi, pourquoi? Qu'est-ce qui se passe ici?
jordanpg
4
à cause de "l'attribut paresseux", voir: github.com/thoughtbot/factory_girl/blob/master
...
9
Malheureusement, cela ne fonctionne pas toujours. Cela obtient simplement un nouvel objet faker aléatoire, mais à cause de RNG, il y a toujours une chance que cela échoue.
Michael Lynch
45

Notez que Faker peut toujours fournir des données en double en raison de la quantité limitée de fausses données disponibles.

À des fins de test simples et pour obtenir des validations d'unicité, j'ai utilisé ce qui suit:

sequence(:first_name) {|n| Faker::Name::first_name + " (#{n})"}
sequence(:last_name) {|n| Faker::Name::last_name + " (#{n})"}
Deux foisB
la source
3
Cette réponse mérite plus de votes positifs. Cela se produira probablement lorsque votre test crée de nombreuses instances.
Enrico Carlesso
Oui, je suis d'accord avec Enrico. +1
karlingen
Bonne idée, mais l'ajout de parenthèses peut casser le reste si vous utilisez le prénom et le nom pour générer des e-mails, ou si vous avez des validations sur le format (je ne connais aucun nom qui a des parenthèses: P).
Cyril Duchon-Doris
18

Dans un souci de préserver la bonne réponse, ici elle est transférée du blog, je ne prends aucun crédit pour la réponse.

Si vous utilisez le code ci-dessous, faker ne produira pas de noms uniques

Factory.define :user do |u|
  u.first_name Faker::Name.first_name
  u.last_name Faker::Name.last_name
end

Cependant, mettre des accolades autour de faker le fait fonctionner!

Factory.define :user do |u|
  u.first_name { Faker::Name.first_name }
  u.last_name { Faker::Name.last_name }
end

Pour expliquer pourquoi, le premier exemple produit les mêmes noms. Il n'évalue qu'une seule fois. Le deuxième exemple évalue chaque fois que l'usine est utilisée.

Cela est dû à la {}fourniture d'une évaluation paresseuse. Ils fournissent essentiellement un proc / lambda avec l'appel Faker comme valeur de retour.

ocodo
la source
Merci d'avoir posté ceci. Je ne pouvais pas comprendre pourquoi Faker n'était pas capable de générer des données aléatoires et il me semblait que chaque exemple que je rencontrais montrait comment utiliser le séquençage, ce qui me semblait étrange. Je voulais utiliser Faker pour que chaque enregistrement soit aléatoire et non séquencé. L'ajout d'accolades autour de mes appels Faker a résolu le problème. Simple et élégant!
Blimey85
5

Une alternative (moins efficace) à l'utilisation de séquences lorsque vous avez une validation d'unicité sur un attribut est de vérifier si une valeur proposée existe déjà et de continuer à en essayer de nouvelles jusqu'à ce qu'elle soit unique:

FactoryGirl.define do
  factory :company do
    name do
      loop do
        possible_name = Faker::Company.name
        break possible_name unless Company.exists?(name: possible_name)
      end
    end
  end
end
Dan Kohn
la source