Question

I am using Factory Girl and Faker to create unique test Users. User model has a uniqueness validation on email.

If I nest 2 levels of describe blocks, then some tests will fail because there are duplicate emails. If I don't nest describe blocks, then all the factory calls return unique Users and the tests pass.

Why does Faker generate duplicate emails in the first scenario?

#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 returns the following error:

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
Was it helpful?

Solution

After a few hours banging my head on the table, my colleague found the answer:

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

The factories turned out not to be transactional. The issue disappeared after the following line to spec_helper.rb:

config.use_transactional_fixtures = true

OTHER TIPS

@Dyanisse As you said we need to do following configuration in spec_helper.rb

config.use_transactional_fixtures = true

but Only that is not sufficient. We need to add it in curly brackets to re-evaluate it as follows

auth_token { Faker::Lorem.characters(32) }

It won't work with:

auth_token Faker::Lorem.characters(32)

Faker will still generate duplicate emails eventually. You can either use sequences or check that the email does not yet exist. See Faker is producing duplicate data when used in factory_girl

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top