This blog post is part of a series on testing. Read Part 1 here.
Good things always come in pairs, and that couldn’t be more true when it comes to testing. Like milk and cookies or peanut butter and jelly, test suites and test data are at their best when they’re put together. As we discovered last week, a thoughtful test suite is important when it comes to checking our assumptions. But even the most comprehensive test suite is nothing without the appropriate amount – and type – of test data to support it.
Every Rails application comes with a production, development, and test environment, and good test data is an indication of a well-constructed testing environment. But not all data is created equally. To take a cue from George Orwell, we could go so far as to claim that some forms of test data are more equal than others.
Enter FactoryGirl, a gem that I’ve recently discovered to be the most efficient way and painless way of creating test data within a Rails application. Generating test data is often the culprit for not only a great deal of pain and sufferring, but also some annoying bugs that are hard to catch. In fact, one of the most excruciating bugs I’ve ever dealt with came from a single line of code, meant to create some test data. So it seems fitting that this week we tackle the most dangerous (yet thrilling!) part of testing: generating test data.
Setting Up The Factory Floor
Since we’re implementing
FactoryGirl on top of a Rails application, we’ll work exclusively with the
factory_girl_rails gem, which has been built specifically for this purpose.
Once we’ve added
gem 'factory_girl_rails' to our
Gemfile and run a
bundle install in the terminal, we’re ready to start setting up our factories. We’ll start by creating factories for our
ReadingList model from last week’s post.
/specdirectory, we’ll need to create a
factoriesdirectory. This is where each of the factories for each model will live.
Inside of our
/spec/factories/subdirectory, we’ll create a file for our
ReadingListfactory. The convention for naming factories is to use the plural form of the model name in snake case, with the word “factory” appended to the end. In our case, that file would be named
In our newly-created
ReadingListFactory, we’ll add a block that defines what our
FactoryGirlobject will look like. Every single factory you make for any instance of test data will begin with a block exactly like this one:
- Next, we’ll want to give this test object a name. For this very basic test suite, we only want to test one
ReadingListobject, so we’ll stick with a simple name:
reading_list. Keep in mind that whatever name we give this test object is what we’ll be using to refer to it inside of our tests. Inside of our initial
FactoryGirlblock, we’ll define this specific object like this:
1 2 3 4
- Lastly, we need to define some attributes for our test object. For now, our
ReadingListtest object needs only three columns in the database: one for its
id, one for its
title, and a foreign key of the
Userit belongs to. Here’s what our final test object definition looks like:
1 2 3 4 5 6
Pretty cool, right? We don’t have to give our test object an
FactoryGirl will generate one when we call on it to create a new test object. So what’s that
user line doing in there? Well, it’s creating an association between two factories! When
user, it looks for a file with the path
/spec/factories/user_factory.rb, and creates an instance of a
User test object, which it then uses to build our
But right now, our code will give us a big, nasty error. Can you guess the reason behind that? Why, we don’t have a
User factory, of course! I guess we better get on that.
Form Follows Function
Now that we know how to set up our factories pretty quickly, we can hop on making a
users_factory. For now, our
User objects have only a
first_name and a
last_name attribute, so we’ll create a
User test object that satisfies these requirements.
Users can also be
admins, but this is an optional trait that not all
Users will have. This is something we definitely want to test, but we also want to keep our code DRY. How do we handle this? By nesting factories!
1 2 3 4 5 6 7 8 9 10
This tells FactoryGirl to define two different
user instances: a
user test object, and an
admin test object, which inherits the traits of the
user object – namely, its
While we’re at it, why don’t we set up our
books_factory as well? That might look something a little like this:
1 2 3 4 5 6 7 8 9 10 11 12 13
Wait, what’s up with the
class: Book syntax? We haven’t seen that yet! Well, not to worry – you only have to use it in a specific situation! What exactly is that situation, you might ask? Well, the only time you ever need to explicitly define a FactoryGirl object’s class is if the name of the object –
book2 in our case – is different from the object’s class name. If we had only a single
book test object, we wouldn’t have to define the class name, since FactoryGirl will know to look for it in the
Remember last week when we had to manually create two different
Book objects every single time we wanted to create a new test object? Well, here we’re defining two test objects in a singular, isolated place.
Awesome! Now it’s time to bring it all together in our cleaned-up test suite!
Bypassing Testing Bugs
When we wrote out the first iteration of our test suite last week, we had a few different
let blocks, inside of which we called
build on our different objects. Our
let blocks definintely helped us tidy up our tests, since we built and created all of our test objects at once, at the very top of our
But as is the case with most of programming, there’s a better way to do that. Now that we’ve implemented FactoryGirl, we can cut out some of those blocks, and only call them when we need them. And, we don’t need to create an instance with the attributes explicitly defined in a block – instead, we just tell FactoryGirl to create it for us!
Here’s a refactored version of last week’s tests, now with the
factory_girl_rails to help us out:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
You’ll notice that I’ve replaced
create in this iteration of tests. I initially had used
build, but when I started implementing FactoryGirl, I hit a wall. In fact, I spent an unmentionable number of hours trying to figure out what on earth I was doing wrong!
It turns out I was using the wrong tool for the job. The
build method creates an instance, but does not save it. The
create method, on the other hand, both creates and persists the object. This was one of the most important debugging lesson I learned while writing tests, and it was not a fun lesson to learn. I hope that at the very least, you won’t have to struggle through that bug like I did!
The thing that I valued the most during this debugging process was learning how
FactoryGirl actualy works. If those
create methods seem an awful lot like ActiveRecord to you, that’s because it IS ActiveRecord!
In fact, when we call
create(:book1), the magic of
FactoryGirl actually does the following:
- Creates a new
- Saves the
- Creates a new
- Associates that
- Saves the
Amazing, right? We get so much functionality, all in a single method call! Learning this made me appreciate what
FactoryGirl does so much more than if I had just included it blindly in my
Gemfile without giving it a second though.
Thoughtbot, the creators of the
factory_girl gem, has a great post explaining how it interacts with ActiveRecord. I found their explaination super helpful when I was first learning about FactoryGirl:
When you invoke a factory, factory_girl uses your definitions to compile a list of attributes that should be assigned to that instance, as well as any associated factories. It saves associations first so that foreign keys will be properly set on dependent models. To create an instance, it calls new without any arguments, assigns each attribute (including associations), and then calls save!. factory_girl doesn’t do anything special to create ActiveRecord instances. It doesn’t interact with the database or extend ActiveRecord or your models in any way.
Sure, when it comes to the world of testing, the night may be dark and full of terrors. But with
FactoryGirl on your side, you’ll feel safer, as though you’ve got an army of dragons to back you up. In my head, they’re super cute ones kinda like these:
Tune in again next week, when I’ll cap off this series by sharing two more gems we can add to our army of testing dragons:
shoulda-matchers for writing quick and easy validations, and
database_cleaner, the key to unlocking your dreams of a neat and tidy testing database. Until then, test on, my friends – test on!
factory_girl_railsgem is used to generate test data for a Rails application, and each factory defines the attributes and associations of a test object. All factory files should be created in the
- This post only covers a couple of the tricks that
FactoryGirlhas up her sleeve. To read them all, check out the gem’s extensive documentation.
- This tutorial is super detailed and I referred to it frequently while writing this blog post. If you want to learn more about testing and implementing
FactoryGirl, give it a read.
- Did you know that factories and fixtures are actually quite different? No? Well then, you should read this post and get all caught up.