Faker está produciendo datos duplicados cuando se usa en factory_girl


86

Estoy tratando de ingresar algunos datos falsos en una fábrica usando la gema 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

Sin embargo, aunque espero que esto produzca usuarios que tienen diferentes nombres y apellidos, cada uno es el mismo:

>> Factory(:user)
=> #<User id: 16, email: "user7@blow.com", 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: "user8@blow.com", created_at: "2011-03-18 18:29:39", 
updated_at: "2011-03-18 18:29:39", first_name: "Bailey", last_name: "Durgan">

¿Cómo puedo hacer que la gema Faker genere nuevos nombres para cada usuario y no solo reutilice los originales?


1
Solo un disparo en la oscuridad, pero ¿has intentado usar algo como user.sequence(:first_name} {|n| Faker::Name::first_name}? Es probable que FactoryGirl solo esté evaluando su llamada de Faker cuando carga sus "accesorios". Usar el sequence param,&blockmétodo debería prevenir eso.
Steven

Respuestas:


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

Intente poner paréntesis alrededor de los falsificadores. ver este enlace


8
Amo tanto stackoverflow - gracias Will, salvaste mi tocino
Peter Nixey

Gracias, esto solucionó mi problema.
Naranjas 13 de

5
¿Por qué, por qué, por qué? ¿Que esta pasando aqui?
jordanpg

4
debido al "atributo perezoso", consulte: github.com/thoughtbot/factory_girl/blob/master/…
Siwei Shen 申思维

9
Lamentablemente, esto no siempre funciona. Básicamente, esto solo obtiene un nuevo objeto falso aleatorio, sin embargo, debido al RNG, todavía existe la posibilidad de que esto falle.
Michael Lynch

45

Tenga en cuenta que Faker puede seguir proporcionando datos duplicados debido a la cantidad limitada de datos falsos disponibles.

Para propósitos de prueba simples y para obtener validaciones de unicidad, he usado lo siguiente:

sequence(:first_name) {|n| Faker::Name::first_name + " (#{n})"}
sequence(:last_name) {|n| Faker::Name::last_name + " (#{n})"}

3
Esta respuesta merece más votos a favor. Es probable que suceda cuando su prueba cree muchas instancias.
Enrico Carlesso

Sí, estoy de acuerdo con Enrico. +1
karlingen

Buena idea, pero agregar paréntesis puede romper el resto si usa el nombre y apellido para generar correos electrónicos, o si tiene validaciones en el formato (no conozco ningún nombre que tenga paréntesis: P).
Cyril Duchon-Doris

18

En aras de preservar la respuesta correcta, aquí se translocó del blog, no me atribuyo el mérito de la respuesta.

Si usa el siguiente código, faker no producirá nombres únicos

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

Sin embargo, poner tirantes alrededor de faker lo hace funcionar.

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

Para explicar por qué, el primer ejemplo produce los mismos nombres. Solo se evalúa una vez. El segundo ejemplo evalúa cada vez que se usa la fábrica.

Esto se debe a que {}proporciona una evaluación perezosa. Básicamente, están proporcionando un proc / lambda con la llamada Faker como valor de retorno.


Gracias por publicar esto. No podía entender por qué Faker no podía generar datos aleatorios y parecía que cada ejemplo que encontraba mostraba cómo usar la secuenciación, lo que me parecía extraño. Quería usar Faker para que cada registro sea aleatorio, no secuenciado. Simplemente agregando llaves alrededor de mis llamadas Faker resolvió el problema. ¡Simple y elegante!
Blimey85

5

Una alternativa (menos eficiente) al uso de secuencias cuando tiene una validación de unicidad en un atributo es verificar si un valor propuesto ya existe y seguir probando otros nuevos hasta que sea único:

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.