At the Forge - Fixtures and Factories

 in
Use factories and fixtures in your Rails applications to help simplify your database-related testing.

instead, I can say this:

one:
  person: one
  meeting: one

two:
  person: two
  meeting: two

Obviously, you would want to choose more descriptive names for your fixtures. But, I now have indicated that meeting #1 is with person #1, and meeting #2 is with person #2. This is obviously more descriptive than the simple numbers would be.

You can even do one better than this, because fixtures understand the has_many :through associations that I defined in the models. Just as in the Ruby code, I can add a person to a meeting with:


meeting.people << a_person

I can put the same sorts of information in the fixture file. For example:

one:
  starting_at: 2009-05-10 00:48:12
  ending_at: 2009-05-10 01:48:12
  location: MyText
  people: one, two
two:
  starting_at: 2009-05-10 00:48:12
  ending_at: 2009-05-10 01:48:12
  location: MyText
  people: two

If you do things this way, you don't want to define things in both the meeting_people fixture and in the meetings fixture. Otherwise, you might be in for some very strange errors. Note that fixture files are ERb (embedded Ruby) files, so you can have dynamically generated entries, such as:


one:
  starting_at: <%= 5.minutes.ago %>
  ending_at: <%= Time.now %>
  location: MyText
  people: one, two

Now, how do you use these fixtures in your tests? It's actually pretty straightforward. You need to load the fixtures you want with the fixtures method:

fixtures :meetings

By default, all fixtures are imported, thanks to:

fixtures :all

in test/test_helper.rb, which is imported automatically into all tests. Then, in your test, you can say something like this:

get :edit, :id => people(:one).id

This example (of a functional test) will load the person object identified as one in people.yml, invoking the edit method and passing it the ID of the appropriate fixture.

Factory Girl

For a small site, or when you can keep everything in your head, fixtures are just fine. I've certainly used them over the years, and I've found them to be an invaluable part of my testing strategy. But, factories are an alternative to fixtures that have become increasingly popular, both because they're written in Ruby code, and they allow you to do all sorts of things that are difficult or impossible with YAML fixtures.

Factory Girl is one of the best known factories, written and distributed by the Thoughtbot company, and it is available as a Ruby gem. After installing Factory Girl on your system and bringing it into your application's environment with:

config.gem "thoughtbot-factory_girl",
             :lib    => "factory_girl",
             :source => "http://gems.github.com"

in config/environment.rb, you will be able to use it. Basically, Factory Girl allows you to create objects in Ruby, rather than load them from fixture files. No defaults are created for you by the generator, but that's not a big deal, given how easy it is to use Factory Girl to create test objects.

Above, I showed how in a test environment using fixtures, you can grab the person object with a name of one by using the people method, and then passing a symbol:

get :edit, :id => people(:one).id

people(:one) is a full-fledged ActiveRecord object, with everything you might expect from such an object. Factory Girl works in a different way. First, you need to create a test/factories.rb file, in which your factories are defined. (You also may create a test/factories/ directory, the contents of which will be Ruby files defining factories.)

To create a factory for people (that is, in place of people.yml), insert people.rb inside test/factories:

Factory.define :person do |p|
  p.first_name 'Reuven'
  p.last_name  'Lerner'
  p.email 'reuven@lerner.co.il'
end

Now, inside the tests, you can say:

get :edit, :id => Factory.build(:person).id

or:

person = Factory.build(:person)
get :edit, :id => person.id

At first glance, this doesn't seem too exciting. After all, you could have done roughly the same thing with your fixture, right? But factories allow you to override the defaults:

person = Factory.build(:person, :first_name => 'Foobar')
get :edit, :id => person.id

But wait, there's more. You can set associations as follows:

Factory.define :person do |p|
  p.first_name 'Reuven'
  p.last_name  'Lerner'
  p.email 'reuven@lerner.co.il'
  p.meetings {|meetings| meetings.association(:meeting)}
end

In other words, if you have created a meeting factory, you can incorporate it into your person factory, taking advantage of the association, using a fairly natural syntax.

An even more interesting idea is that of sequences. If your application needs to create a large number of test people, you might want each of those people to have a unique e-mail address. (Never mind that the e-mail never will be sent.) You can do this with a sequence:

Factory.define :person do |p|
  p.first_name 'Reuven'
  p.last_name  'Lerner'
  p.sequence(:email) {|n| "person#{n}@example.com" }
end

The first person created with this factory will have an e-mail address of person1@example.com; the second will be person2@example.com and so forth.

As you can see, Factory Girl is as easy to use as YAML fixtures, but it offers a great many capabilities that come in handy when testing Rails applications.

Factory Girl is a terrific library for factories, and it has become quite popular since it was first released. But, not everyone liked its basic syntax, and one of those people was Pete Yandell, who decided that although the basic idea behind factories was sound, he wanted to use a different (and more compact) syntax for his factories. Thus was born Machinist, which uses a Sham object to describe fields in an object, which are then assembled into blueprints for specific objects. For example:

require 'faker'

# Define the fields that we will need
Sham.first_name  { Faker::Name.first_name }
Sham.last_name  { Faker::Name.last_name }
Sham.email { Faker::Internet.email }

# Now use these field definitions to create a blueprint
Person.blueprint do
  first_name
  last_name
  email
end

Now you can use these blueprints to create test objects. For example:

person = Person.make()

As with Factory Girl, you also can override the defaults:

person = Person.make(:email => 'foo@example.com')

______________________

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix