Faker在factory_girl中使用时会产生重复数据

87
我正在尝试使用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 gem 为每个用户生成新的名称而不是重复使用原来的名称?


1
这只是一个猜测,但你是否尝试使用类似 user.sequence(:first_name} {|n| Faker::Name::first_name} 的东西?当加载“固定装置”时,FactoryGirl可能只会评估您的Faker调用。使用sequence param,&block方法应该可以防止这种情况发生。 - Steven
4个回答

159
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

尝试在fakers周围加上括号。请参考此链接


8
我非常喜欢stackoverflow - 谢谢Will,你救了我的一大把。 - Peter Nixey
5
为什么,为什么,为什么?这里到底发生了什么? - jordanpg
4
由于"懒惰属性",请参见: https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#lazy-attributes - Siwei
10
遗憾的是,这并不总是有效。这基本上只是获取一个新的随机模拟对象,但由于随机数生成器的原因,仍然有可能失败。 - Michael Lynch
这就是为什么编写Rails应用程序只能依靠Stack Overflow的原因。谢谢。 - JD.
有没有办法修复随机数生成器(RNG)? - MrMesees

46

请注意,由于可用虚假数据数量有限,Faker可能仍会提供重复数据。

为了进行简单的测试并绕过唯一性验证,我使用了以下内容:

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

3
这个回答值得更多的赞。当您的测试创建了许多实例时,这很可能会发生。 - Enrico Carlesso
是的,我同意Enrico的观点。+1 - karlingen
好主意,但是如果您使用名字和姓氏生成电子邮件,或者在格式上进行验证(不知道有哪个名字带括号:P),添加括号可能会破坏其他部分。 - Cyril Duchon-Doris

18
为了保持正确答案,这里将其从博客转移过来,我不为此负责。

如果使用以下代码,faker将无法生成独特的名称

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

然而,在faker周围加上花括号可以让它工作!
Factory.define :user do |u|
  u.first_name { Faker::Name.first_name }
  u.last_name { Faker::Name.last_name }
end

为了解释其中的原因,第一个示例产生了相同的名称。它只被评估一次。而第二个示例在每次使用工厂时都会被评估。
这是由于`{}`提供了惰性的求值方式。本质上,它们为Faker调用提供一个proc/lambda作为其返回值。

谢谢你的发帖。我之前一直搞不清楚为什么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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接