How split factory_girl definitions across many files?
Asked Answered
P

3

12

My factories.rb file became too big to maintain over time and I'm now trying to split it across many files in factories directory. The problem is that I don't know how to deal with dependencies.

To make a long story short, I'm trying to split my factories in following way. All sequences go to sequences.rb file and each factory definition goes to separate file like so:

factories/sequences.rb

FactoryGirl.define do
   sequence :name {|n| "Name #{n}" }
   sequence :email {|n| "person#{n}@example.com" }
end

factories/user.rb

FactoryGirl.define do
    factory :user do
        name
        email
    end
end

factories/post.rb

FactoryGirl.define do
    factory :post do
        name
        content "Post Content"
        user
    end
end

When I run tests I get name is not defined error. I can deal with this by passing a block to each association (e.g. name, email, user and so on) mention but it seems to be ugly and not DRY.

  1. Is there way to let factory_girl know sequence in which files should be loaded?
  2. to deal with complex dependencies when it's not possible to fix this issue with changing load sequence of files?
Patriotism answered 26/5, 2014 at 3:16 Comment(2)
would the Faker Gem be an alternative to those sequences? I find them ugly to be honest...Photoelectron
As @TheCha͢mp indicates use FFaker gem or something similar (Forgery) for this. it is a solved problem IMO, I've gone down the route of sequences and that way lies madness.Curran
P
7

You can simply achieve the result with generate method:

# factories/sequences.rb
FactoryGirl.define do
  sequence(:email) { |n| "person#{n}@example.com" }
end

# factories/user.rb
FactoryGirl.define do
  factory :user do
    email { generate(:email) }
    password '12345678'
  end
end

Then try it:

FactoryGirl.create :user
=> #<User:0x007fa99d2ace40
 id: 1,
 email: "[email protected]",
 . . .>

Sequences Documentation for more details.

Prosaic answered 21/11, 2016 at 19:57 Comment(0)
C
1

I do this in this way:

  1. Create separate folder for shared factories. It should in same level as 'factories' folder.

factories

shared_factories

  1. Create shared file, ex. shared_factories/sequences.rb

  2. Import sequences.rb to every factory file. require_relative '../shared_factories/sequences'

The full example:

https://gist.github.com/alexkojin/6a2d70f84ff91c37315d1d3edb0d8e6b

Chime answered 21/11, 2016 at 9:22 Comment(1)
FactoryGirl doesn't allow put shared resources in factories folder. It will raise DuplicationError.Chime
K
-3

You can do this:

FactoryGirl.define do
    factory :user do
        sequence(:name) {|n| "Name #{n}" }
        sequence(:email) {|n| "person#{n}@example.com" }
    end
end

FactoryGirl.define do
    factory :post do
        content "Post Content"
        user { create :user }
    end
end

There are a variety of ways to structure your factory girls factories such as traits, inheritance, callbacks, etc. I just recently learned about traits and it is really wonderful:

FactoryGirl.define do
    factory :user do
        sequence(:name) {|n| "Name #{n}" }
        sequence(:email) {|n| "person#{n}@example.com" }
    end

    trait :with_post do
        after(:create) { |user| create :post, user: user }
    end
end

FactoryGirl.define do
    factory :post do
        content "Post Content"
        user { create :user }
    end
end

# and in your specs you will do this:
let!(:blogger) { create :user, :with_post }

It is very worthwhile to invest some time reading through the entire documentation (a 30 mins read perhaps?). Thereafter, you will have much better ideas to refactor your factories.

Reference link: https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md

Kain answered 26/5, 2014 at 7:21 Comment(1)
The question is clearly about how to split up all the factories across different files.Clari

© 2022 - 2024 — McMap. All rights reserved.