如果在描述块中调用 Factory Girl 为啥会创建重复项

Posted

技术标签:

【中文标题】如果在描述块中调用 Factory Girl 为啥会创建重复项【英文标题】:Why does Factory Girl create duplicates if called in describe blocks如果在描述块中调用 Factory Girl 为什么会创建重复项 【发布时间】:2013-06-25 09:37:09 【问题描述】:

我正在使用 Factory Girl 和 Faker 来创建独特的测试用户。 用户模型在电子邮件上具有唯一性验证。

如果我嵌套 2 级描述块,那么一些测试将失败,因为有重复的电子邮件。 如果我不嵌套描述块,那么所有工厂调用都会返回唯一用户并且测试通过。

为什么 Faker 在第一种情况下会生成重复的电子邮件?

#factories/user.rb

# a simple factory with Faker
FactoryGirl.define do
  factory :student, class: User do
    first_name  Faker::Name.first_name 
    last_name  Faker::Name.last_name 
    password  Faker::Lorem.words(3).join 
    email  Faker::Internet.email 
  end
end

#spec/models/user_spec.rb   

# in this test structure, Faker returns duplicate emails
describe "nested describe blocks" do
  describe "block 1" do
    it "creates faker duplicates" do 
      10.times
        FactoryGirl.create(:student)
      
    end
   end
  describe "block 2" do 
    it "creates faker duplicates" do 
      10.times
        FactoryGirl.create(:student)
      
    end
  end
end

# in this structure, Faker emails are unique
describe "no nested describe blocks" do     
  it "doesn't create duplicates" do 
    10.times
      FactoryGirl.create(:student)
    
  end      
  it "doesn't create duplicates" do
    10.times
      FactoryGirl.create(:student)
    
  end      
end

Rspec 返回以下错误:

Failure/Error: FactoryGirl.create(:student)
 ActiveRecord::RecordInvalid:
   Validation failed: Email has already been taken, Email has already been taken, Authentication token has already been taken

【问题讨论】:

您介意发布您的错误输出吗? 我获取了您的文件并在我的机器上成功运行了它们,但在此过程中,遇到了 Rails 使用 spork 在后台运行的问题,这使我无法在我的工厂定义并导致您看到的相同验证错误。这是一个很长的镜头,但是当您运行测试时,您确定 Rails 没有在其他进程中运行吗?另外,我觉得奇怪的是你有多个错误短语,用逗号分隔。你知道为什么吗?最后,我建议在每次创建记录后更改测试以打印电子邮件地址以查找副本。 【参考方案1】:

我的头在桌子上敲了几个小时后,我的同事找到了答案:

Why isn't factory_girl operating transactionally for me? - rows remain in database after tests

事实证明,这些工厂不是交易型的。在 spec_helper.rb 的以下行之后问题就消失了:

config.use_transactional_fixtures = true

【讨论】:

【参考方案2】:

@Dyanisse 正如你所说,我们需要在 spec_helper.rb 中进行以下配置

config.use_transactional_fixtures = true

但仅此还不够。我们需要将它添加到大括号中以重新评估它,如下所示

auth_token  Faker::Lorem.characters(32) 

它不适用于:

auth_token Faker::Lorem.characters(32)

【讨论】:

【参考方案3】:

Faker 最终仍会生成重复的电子邮件。您可以使用序列或检查电子邮件是否尚不存在。见Faker is producing duplicate data when used in factory_girl

【讨论】:

以上是关于如果在描述块中调用 Factory Girl 为啥会创建重复项的主要内容,如果未能解决你的问题,请参考以下文章

在 factory_girl 中填充与儿童的关联

访问 *other* 工厂中的 factory_girl 工厂

在具有唯一约束的关联中使用 Rails 中的 factory_girl。得到重复的错误

Factory Girl + Mongoid 在夹具中嵌入文档

跳过 Factory Girl 和 Rspec 的回调

测试时我应该在 Factory girl 中还是在规范文件中存根模型?