If you are used to testing with Rails, chances are you already know FactoryGirl, the de facto standard substitute for fixtures, and you are used to use something like this on your tests:

FactoryGirl.create(:classroom)

...relying on your Classroom factory:

factory :classroom do |f|
  sequence(:name)  { |n| "Class #{n}}" }
  active true
  teacher
end

Well in this post I'll show you some advanced uses of FactoryGirl to go a bit beyond the basics, tips & tricks you'll love and will be eager to experiment with and use on your next projects.

Don't repeat yourself

Having to type FactoryGirl. seems a little thing, but if you count how many times you do it in the development of a project, that's A LOT. So, the first thing would be mixin FactoryGirl methods in your spec helper:

# File spec/spec_helper.rb
RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
end

If you are using other than RSpec, check the docs to find your equivalent.

Now that we are properly set up, let's continue...

I heard you like traits...

Traits are a very nice way of having at hand ways to create objects with additional certain properties, let's say we need to use a classroom with students on it on our tests, or a classroom with a support_teacher:

factory :classroom do |f|
  sequence(:title)  { |n| "Class #{n}}" }
  active true
  teacher

  trait :with_students do
    after(:build) do |classroom|
      create(:student, classroom: classroom)
    end
  end

  trait :with_support_teacher do
    after(:create) do |classroom|
      classroom.support_teacher = create(:teacher)
    end
  end
end

Then if we wanted to use in our tests an article with comments that is also on frontpage, we could do:

create(:classroom, :with_students, :with_support_teacher)

Or going a bit further we can create a trait that uses traits itself:

trait :full_class do
  with_students
  with_support_teacher
end

And then beautifully do:

create(:classroom, :full_class)

But I need them in large numbers!

Our previous trait with_students is not really faithful to its name, but it would be very easy to correct with the create_pair method:

trait :with_students do
  after(:build) do |classroom|
    create_pair(:student, classroom: classroom)
  end
end

That will give you two students in our classroom. But let's say we want more, a very populated classroom full of noisy children:

trait :with_students do
  after(:build) do |classroom|
    create_list(:student, 25, classroom: classroom)
  end
end

Even more, what if we wanted to be able to set the number of students each time we use the factory, instead of having a prefixed amount? That's when ignored attributes and the evaluator come in handy.

Ignored attributes are not used on factory creation (i.e.: not set on the created object), and are handy to store or pass data we want to use in callbacks or traits, via the evaluator, this way:

trait :with_students do
  ignore do
    number_of_students 10
  end

  after(:build) do |classroom, evaluator|
    create_list(:student, evaluator.number_of_students, classroom: classroom)
  end
end

In short, ignored attributes would set our default values, but allow us to set them as we wish, so these two are valid:

 create(:classroom, :with_students) # would still give us 10 students in the classroom
 create(:classroom, :with_students, number_of_students: 7)

Photo by Biczzz on Flickr