Faker производит повторяющиеся данные при использовании в factory_girl

86

Я пытаюсь заполнить фабрику фальшивыми данными с помощью драгоценного камня 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

Однако, хотя я ожидаю, что это приведет к появлению пользователей с разными именами first_name и last_name, все они одинаковы:

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

Как я могу заставить гем Faker генерировать новые имена для каждого пользователя, а не просто повторно использовать оригинальные?

Питер Никси
источник
1
Просто выстрел в темноте, но пробовали ли вы использовать что-то вроде user.sequence(:first_name} {|n| Faker::Name::first_name}? FactoryGirl, скорее всего, просто оценивает ваш вызов Faker, когда загружает ваши «приспособления». Использование sequence param,&blockметода должно предотвратить это.
Стивен

Ответы:

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

Попробуйте заключить фейков в скобки. см. эту ссылку

Уилл Айд
источник
8
Я так люблю stackoverflow - спасибо, Уилл, ты спас мой бекон
Питер Никси
Спасибо, это устранило мою проблему!
Апельсины 13
5
Почему, почему, почему? Что здесь происходит?
jordanpg
4
из-за «ленивого атрибута», см .: github.com/gotitbot/factory_girl/blob/master/…
Siwei Shen 申思维
9
К сожалению, это не всегда работает. По сути, это просто получает новый случайный объект-фейкер, однако из-за RNG все еще есть шанс, что это не удастся.
Майкл Линч,
45

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

Для простых целей тестирования и проверки уникальности я использовал следующее:

sequence(:first_name) {|n| Faker::Name::first_name + " (#{n})"}
sequence(:last_name) {|n| Faker::Name::last_name + " (#{n})"}
ДваждыB
источник
3
Этот ответ заслуживает большего количества голосов. Это может произойти, когда ваш тест создает много экземпляров.
Энрико Карлессо
Ага, я согласен с Энрико. +1
karlingen
Хорошая идея, но добавление круглых скобок может нарушить все остальное, если вы используете имя и фамилию для создания электронных писем или у вас есть проверки формата (не знаю ни одного имени, в котором есть круглые скобки: P).
Сирил Дюшон-Дорис
18

Чтобы сохранить правильный ответ, здесь он перенесен из блога, я не беру на себя ответственность за ответ.

Если вы используете приведенный ниже код, faker не будет выдавать уникальные имена

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

Однако фигурные скобки вокруг фейкер заставляют его работать!

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

Чтобы объяснить, почему, в первом примере используются те же имена. Это только оценка один раз. Во втором примере выполняется оценка каждый раз, когда используется фабрика.

Это происходит из-за {}ленивой оценки. По сути, они предоставляют proc / lambda с вызовом Faker в качестве возвращаемого значения.

окодо
источник
Спасибо за публикацию. Я не мог понять, почему Faker не может генерировать случайные данные, и казалось, что каждый пример, с которым я сталкивался, показывает, как использовать секвенирование, что мне показалось странным. Я хотел использовать Faker, чтобы каждая запись была случайной, а не последовательной. Простое добавление скобок вокруг моих вызовов Faker решило проблему. Просто и элегантно!
Blimey85
5

Менее эффективная альтернатива использованию последовательностей, когда у вас есть проверка уникальности атрибута, - это проверить, существует ли уже предлагаемое значение, и продолжать пробовать новые, пока не станет уникальным:

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
Дэн Кон
источник