How to create/build multiple instances of a factory in Factory Girl?
Asked Answered
F

4

28

How do I create multiple records or multiple factories of the same class?

I tried:

Factory.define :user do |user|
  user.email "[email protected]"
  user.password "somepassword"

  user.email "[email protected]"
  user.password "somepassword"
end

and

Factory.define :user do |user|
  user.email "[email protected]"
  user.password "somepassword"
end

Factory.define :user do |user|
  user.email "[email protected]"
  user.password "somepassword"
end

But it doesn't work -- Attribute already defined: email.

Flosser answered 1/4, 2011 at 6:14 Comment(0)
I
23

There are two steps to using Factories, the first is to define them, and the second is to use them.

1) Define Them:

Factory.define :user do |u|
  u.sequence(:email) { |n| "mike#{n}@awesome.com"}
  u.password "password123"
end

2) Using Them:

An example would be to use them in a spec:

 @user1 = Factory(:user) #has an email of [email protected]
 @user2 = Factory(:user) # has an email of [email protected] due to sequences in FG

I'd watch this Railscast to get a better feel for it.

Instrumentation answered 1/4, 2011 at 6:18 Comment(0)
G
49

This is an older question and answer but it was the first result I found on Google so I thought I would add the following from the docs under the heading Building or Creating Multiple Records:

created_users = FactoryBot.create_list(:user, 25)  #creates 25 users

twenty_year_olds = FactoryBot.build_list(:user, 25, date_of_birth: 20.years.ago)  #builds 25 users, sets their date_of_birth

If you want to run this in the rails console, consider the following answer here: https://mcmap.net/q/194311/-how-do-i-use-factories-from-factorybot-in-rails-console

In the example I just cited, each user would have a different username, provided that sequence is used in the factory definition (see Mike Lewis' answer above).

Gaggle answered 20/6, 2013 at 18:0 Comment(1)
Brilliant! Thanks for coming back to an old question and giving an updated answer.Ectoblast
P
37

There's a couple of options if you want records from the same (base) factory to have different values.

A) Override defined attributes

factory :post, aliases: [:approved_post] do
  title "A title"
  approved true
end

approved_post = create(:approved_post)
unapproved_post = create(:post, approved: false)

B) Inheritance

factory :post do
  title "A title"

  factory :approved_post do
    approved true
  end

  factory :unapproved_post do
    approved false
  end
end

approved_post = create(:approved_post)
unapproved_post = create(:unapproved_post)

C) Sequences

factory :user do
  sequence(:email, 1000) { |n| "person#{n}@example.com" }
end

D) Traits

factory :post do
  title "My awesome title"

  trait(:approved) { approved true }

  trait(:unapproved) { approved false }

  trait :with_comments do
    after(:create) do |instance|
      create_list :comment, 2, post: instance
    end
  end

  factory :approved_post_with_comments, traits: [:approved, :with_comments]
end

approved_post_with_comments = create(:approved_post_with_comments)
unapproved_post_with_no_comments = create(:post, :unapproved, title: "Test")
post_with_title = build(:post)

These methods can be combined. This example uses lists and pairs with sequences and overriding.

factory :user do
  sequence(:username) { |n| "user#{n}" }
  date_of_birth Date.today
end

# Build a pair and a list of users.
two_newborns     = build_pair(:user)
ten_young_adults = build_list(:user, 10, date_of_birth: 20.years.ago)

# Create a pair and a list of users.
two_young_adults = create_pair(:user, date_of_birth: 20.years.ago)
ten_newborns     = create_list(:user, 10)

I prefer to use traits whenever possible, I find them flexible.

Piscatelli answered 19/6, 2014 at 14:35 Comment(0)
I
23

There are two steps to using Factories, the first is to define them, and the second is to use them.

1) Define Them:

Factory.define :user do |u|
  u.sequence(:email) { |n| "mike#{n}@awesome.com"}
  u.password "password123"
end

2) Using Them:

An example would be to use them in a spec:

 @user1 = Factory(:user) #has an email of [email protected]
 @user2 = Factory(:user) # has an email of [email protected] due to sequences in FG

I'd watch this Railscast to get a better feel for it.

Instrumentation answered 1/4, 2011 at 6:18 Comment(0)
S
0

With the current factory_girl_rails 4.6.0 I had the somehow related problem that build(:model) returned always the same instance of the object. Using sequence(:name) ... didn't fix that. So I generated some fake (empty) traits like this:

FactoryGirl.define do
  factory :model do
     ...
     # fake traits to urge factory_girl to always return a new instance:
    (1..5).each {|n| trait "var#{n}".to_sym }
  end
end

And then calling build(:model, :var1), build(:model, :var2)...

Swansea answered 29/2, 2016 at 16:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.