Faker tworzy zduplikowane dane, gdy jest używany w factory_girl

86

Próbuję wprowadzić fałszywe dane do fabryki za pomocą klejnotu Fakera:

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

Jednak chociaż spodziewam się, że spowoduje to utworzenie użytkowników, którzy mają różne imię i nazwisko, każdy z nich jest taki sam:

>> 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">

Jak mogę sprawić, by klejnot Fakera generował nowe nazwy dla każdego użytkownika, a nie tylko ponownie używał oryginalnych?

Peter Nixey
źródło
1
Tylko strzał w ciemności, ale czy próbowałeś użyć czegoś takiego user.sequence(:first_name} {|n| Faker::Name::first_name}? FactoryGirl prawdopodobnie właśnie ocenia wywołanie Fakera, gdy ładuje Twoje „urządzenia”. Zastosowanie tej sequence param,&blockmetody powinno temu zapobiec.
Steven

Odpowiedzi:

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

Spróbuj umieścić nawiasy wokół oszustów. zobacz ten link

Will Ayd
źródło
8
Tak bardzo kocham stackoverflow - dziękuję Will, uratowałeś mój bekon
Peter Nixey
Dziękuję, to rozwiązało mój problem!
Pomarańcze 13
5
Dlaczego dlaczego dlaczego? Co tu się dzieje?
jordanpg
4
z powodu „leniwego atrybutu”, patrz: github.com/thoughtbot/factory_girl/blob/master/…
Siwei Shen 申思维
9
Niestety nie zawsze to działa. To w zasadzie dostaje nowy losowy obiekt fałszywego, jednak z powodu RNG nadal istnieje szansa, że ​​to się nie powiedzie.
Michael Lynch,
45

Pamiętaj, że Faker może nadal dostarczać zduplikowane dane ze względu na ograniczoną liczbę dostępnych fałszywych danych.

Do prostych celów testowych i walidacji unikalności użyłem:

sequence(:first_name) {|n| Faker::Name::first_name + " (#{n})"}
sequence(:last_name) {|n| Faker::Name::last_name + " (#{n})"}
Dwa razy B.
źródło
3
Ta odpowiedź zasługuje na więcej głosów. Jest to prawdopodobne, gdy test tworzy wiele instancji.
Enrico Carlesso
Tak, zgadzam się z Enrico. +1
karlingen
Niezły pomysł, ale dodanie nawiasów może zepsuć resztę, jeśli używasz imienia i nazwiska do generowania wiadomości e-mail lub masz walidację formatu (nie znasz żadnej nazwy, która ma nawias: P).
Cyril Duchon-Doris
18

W celu zachowania poprawnej odpowiedzi, tutaj została przeniesiona z bloga, nie przypisuję sobie zasługi.

Jeśli użyjesz poniższego kodu, faker nie wypuści unikalnych nazw

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

Jednak założenie szelek kręconych wokół fakera sprawia, że ​​działa!

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

Aby wyjaśnić, dlaczego, pierwszy przykład przedstawia te same nazwy. Ocenia się tylko raz. Drugi przykład ocenia za każdym razem, gdy używana jest fabryka.

Wynika to z {}leniwej oceny. Zasadniczo dostarczają proc / lambda z wywołaniem Fakera jako wartością zwracaną.

ocodo
źródło
Dziękuję za opublikowanie tego. Nie mogłem zrozumieć, dlaczego Faker nie był w stanie wygenerować losowych danych i wyglądało na to, że każdy napotkany przykład pokazuje, jak używać sekwencjonowania, co wydawało mi się dziwne. Chciałem użyć Fakera, więc każdy rekord jest losowy, a nie sekwencyjny. Samo dodanie nawiasów klamrowych wokół moich połączeń Fakera rozwiązało problem. Prosty i elegancki!
Blimey85
5

(Mniej wydajną) alternatywą dla używania sekwencji, gdy masz walidację unikalności atrybutu, jest sprawdzenie, czy proponowana wartość już istnieje i próbowanie nowych, aż będzie unikalna:

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
źródło