In my current job we were facing a well known problem called Fixtures. The term Fixtures in context of Ruby On Rails framework is the default way how the testing data are prepared/created before the tests run.
Here’s the list of important reasons why Fixtures are pain:
- Hard to read (YAML format)
- Hard to define edge cases
- Almost impossible to modify after reaching certain size of fixtures
The only real reason for using fixtures which I can find is speed. So if you’re on small project or you really need to have tests running fast then the fixtures are good choice. But if you need to have easy to read tests with test data, possibility to easily modify them and having be able to define a lot of edge cases here’s one nice possible way to go called Design Patterns.
Factory patterns (http://en.wikipedia.org/wiki/Factory_pattern)
In these days people are already using Factory pattern as replacement for Fixtures and you can find plenty libraries to help you simplify the work:
At the end we decided to go for FactoryGirl because it’s widely used which means there’s a lot of people to help us with answering questions and fixing bugs.
Example of FactoryGirl:
1 2 3 4 5 6 7 8 9
| Factory.define :invoice, :class => Invoice do |u|
u.created_at 2.days.ago
u.started_at 2.months.ago.beginning_of_month
u.ended_at 2.months.ago.end_of_month
end
Factory.define :invoice_with_billing_cycle, :parent => :invoice do |u|
u.association :billing_cycle, :factory => :billing_cycle_2_months_ago
end |
Personally I also like very much Foundry by Jeremy McAnally. The only disadvantage is that it’s closely linked with Ruby On Rails named_scopes implementation.
Builder pattern (http://en.wikipedia.org/wiki/Builder_pattern)
This pattern isn’t yet widely used as Factory in Ruby On Rails community. I really don’t know why, but I didn’t find any article about using it so here we go.
I like to use this design pattern in situations when:
- You need to create complex object structures (together with Factory)
- You need to be flexible with creating many edge cases
The best thing about using Builder pattern is that you don’t need any library but just pure Ruby objects.
Example of Builder pattern in Ruby combined with Factory girl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class InvoiceBuilder
def initialize(invoice_factory, options = {})
@invoice_factory = invoice_factory
@options = options
self
end
def with_line_items(line_items)
@line_items = line_items
self
end
def create
invoice = Factory(@invoice_factory.to_sym, @options)
@line_items.each do |li|
li_factory, li_options = li
invoice.line_items << Factory(li_factory.to_sym,
li_options.merge(:invoice => invoice))
end
invoice
end
end |
The code above shows very flexible way of using Builder pattern to chain your criteria as you need them. You can than write something like this:
1
| InvoiceBuilder.new(:invoice_with_billing_cycle).with_line_items([ item1, item2 ]).create |
Interesting articles to read:
Things to consider:
- Try to keep your tests and Factories simple
- Keep your data very close to your tests
- Create complex structures with Builder pattern
Thanks for reading. Let me know what you think in comments. Any kind of feedback appreciated!