Using Factories for Rails Fixtures and Test Doubles

Chris Wanstrath has written about making Rails fixtures less painful than they need to be with the FixtureScenarios plugin. Personally, I prefer the Factory approach, nicely explained by Daniel Manges.

I’ve been using factory methods to create in-database ActiveRecord objects for a project that I’ve been working on in Bezurk. Reading Daniel’s article gave me a few ideas on improving the way I create fixtures and mocks. Since I’ve been using RSpec extensively in this project, I’ll present the examples in RSpec.

As the models evolve with the design and its behaviour change accordingly, there is a need to go through all the specifications that create this model and make sure that its created in a valid state. This is more pronounced with the use of test doubles, the test doubles also need to have its method stubs changed to reflect the latest state of the model that its is representing. I happen to make much use of test doubles for test isolation, so trying to manage all these objects became an exercise in patience. As it was getting painful, It’s time to change the way I create these models and test doubles.

As always, a layer of indirection will always go some way to solving a software problem. We introduce a Factory that encapsulates the creation of ActiveRecord objects by providing creation methods.

[ruby]
module FixtureFactory
def create_user(attributes = {})
User.create!(ModelAttributes.user(attributes))
end
end
[/ruby]
We’ll have a Factory for test doubles too.

[ruby]
module MockFactory
def mock_user(method_stubs = {})
mock_model(User, ModelAttributes.user(method_stubs))
end
end
[/ruby]
And the attributes for this model will be declared in a module that’s used by both Factories

[ruby]
module ModelAttributes
def self.user(attributes)
attributes.reverse_merge({:name => ‘doug’})
end
end
[/ruby]

The Factory modules are then included in Spec::Runnner

[ruby]
Spec::Runner.configure do |config|
include FixtureFactory
include MockFactory
end
[/ruby]

The objects can now be created using the factory methods available to all specifications.

[ruby]
doug = create_user
doppelganger = mock_user
[/ruby]

Update
Added links to Chris Wanstrath and Daniel Manges’ articles on managing Rails fixtures.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s