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')

______________________

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState