Brandon Rice

Software development with a focus on web technologies.

Rails Fixtures and FactoryGirl

| Comments

I’ve been jumping into Ruby (and specifically Rails) testing in the last few weeks.  I figured I’d share a quick introduction to a neat tool that really has the potential to save time: FactoryGirl. FactoryGirl is a gem that allows you to replace cumbersome Rails fixtures with something much more flexible.  When testing, fixtures allow you to specify some default entries in your database tables which can then be used throughout your tests.  Read more about fixtures here.  A fixtures file might look something like this.

test/fixtures/users.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
bob:
  first_name: Bob
  last_name: Smith
  email: bob@example.com
  position: CEO
  phone: 777-1111

john:
  first_name: John
  last_name: Doe
  email: john@example.com
  position: CTO
  phone: 777-1112
Fixtures are automatically loaded when tests are run. Inside my tests, I would be able to use my fixtures like so.

test/unit/user_test.rb
1
2
3
4
5
6
7
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  test 'Bob should be the CEO' do
    assert_equal users(:bob).position, 'CEO'
  end
end
This is all well and good until you suddenly need to do something slightly outside of the box.  What if you want to quickly generate 3 more test users with unique names?  What if you need a large array of 100 test users?  Fixtures don’t work particularly well in these kinds of scenarios.  Of course, you could also write these particulars into your test’s setup method.  But there’s an easier way.  Enter FactoryGirl.

test/factories/user.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
FactoryGirl.define do
  factory :user do
    sequence(:email) { |n| "test#{n}@example.com" }

    factory :named_user do
      email { "#{first_name}@example.com" }

      factory :user_bob do
        first_name 'Bob'
        last_name 'Smith'
        phone '777-1111'
      end

      factory :user_john do
        first_name 'John'
        last_name 'Doe'
        phone '777-1112'
      end
    end
  end
end
In this one example, I’ve taken care of all of the afore mentioned hypothetical scenarios while still including our original fixtures.  Each model can be associated with many factories.  A factory allows you to manufacture lots of objects of your model class.  Here’s how I might use the factories I defined in place of the earlier unit test.

test/unit/unit_test.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  test 'Run some test examples' do
    # Let's get John and Bob back from the original fixtures
    bob = FactoryGirl.create(:user_bob)
    john = FactoryGirl.create(:user_john)

    # Now let's create 100 unique users
    users = FactoryGirl.create_list(:user, 100)

    # I need a new unique user named Jim
    jim = FactoryGirl.create(:named_user, first_name: 'Jim', last_name: 'Smith')

    # Both of these will pass
    assert_equal jim.email, 'jim@example.com'
    assert_equal users.first.email, 'test1@example.com'
  end
end
Not only have I easily generated some unique users for my tests, but I can sequence unique email addresses for each one with just a couple lines of code in my factory definition.  This is just scratching the surface of what can be done with FactoryGirl.  It has support for callbacks, associations, and so much more.