Lesson Weekend

As our applications become more complex, we can maximize the quality of our testing by implementing testing gems that make writing and analyzing tests easier and more efficient. Before we start writing tests for our Rails API, we'll learn about the gem FactoryBot, which we can use to help us create DRY, thorough tests.

FactoryBot


As we've written our tests, you may have noticed that they can become brittle — easy to break by making small changes. For example, if a model is changed to validate new attributes, every test that creates an instance of that class needs to be changed to reflect the new validations. This is because our test code is not DRY. We can eliminate repetition in our testing code by using FactoryBot.

FactoryBot was originally called FactoryGirl when Thoughtbot first released the gem in 2008. The name was a reference to a Rolling Stones song. However, many people felt that it was problematic to use a gendered name, especially in an industry already lacking in gender and other diversity. You can read about the name change here. We think they made the right call!

While all references to the name FactoryGirl have been removed from the gem and the documentation itself, if you are trying to find answers to technical issues related to FactoryBot, you may also want to do a search for FactoryGirl. There are many blogs, articles and StackOverflow answers that predate the name change.

To add FactoryBot to a project, we simply need to add the factory_bot_rails gem to our Gemfile's :test area and bundle.

Integrating FactoryBot

Let's look at an example of how we can use FactoryBot to make tests DRYer. In the next lesson, we will start writing tests for our Rails API. We'll want to be able to test our GET requests. And as we know, we can use a GET request to return all of the quotes from our API. While we could hard-code twenty quotes — or write a loop to generate twenty quotes in combination with the Faker gem, let's use a factory instead.

To do so, we'll create a file called factories.rb in our spec folder.

spec/factories.rb
FactoryBot.define do
  factory(:quote) do
    author {Faker::Name.name}
    content {Faker::Movie.quote}
  end
end

We can use this factory to quickly generate quotes. For instance, we can do the following in our actual tests:

let!(:quotes) { FactoryBot.create_list(:quote, 20)}

This would generate twenty quotes for us. FactoryBot provides the create_list method which takes two arguments: :quote and the number 20. Note that :quote matches the name of the factory above. When we want to make use of a factory, we need to call it by its name.

One of the really nice things about FactoryBot is that we can easily add additional properties to a factory. For instance, let's say that we want to add a date property. For testing purposes, we only need to do that in one place — in the factory itself. This is all we need to do to add that property in our code:

FactoryBot.define do
  factory(:quote) do
    author {Faker::Name.name}
    content {Faker::Movie.quote}
    date {"today"}
  end
end

We just added the following line: date {"today"}. (It's not as sophisticated as a timestamp but it's fine for this example.) Without factories, we'd need to update every instantiated quote in every test. As you probably recall from updating tests in past sections, that can be a lot of work and lead to errors.

What if we just want to use a single quote in a test — not generate twenty? Here's how we'd do it:

...
  it 'creates a quote' do
    quote = FactoryBot.create(:quote)
    # Some expectation here.
  end
end

We just have to use the FactoryBot.create() method. We can also override the values that FactoryBot generates for us. Here's an example:

...
  it 'creates a quote' do
    quote = FactoryBot.create(:quote, :author => "Ada Lovelace")
    quote.author.should eq "Ada Lovelace"
  end
end

Here, we've overwritten a default attribute of the factory by specifying it explicitly as a second argument: :author => "Ada Lovelace". But we still get the power of being able to change other attributes in the factory without changing them everywhere else.

We'll only use FactoryBot as a convenience for generating additional quotes — but it's an excellent tool for testing in general. We recommend checking outFactoryBot's README, which has a link to their Getting Started page. Check out the Defining Factories section as well. Other topics to explore and implement in your testing with FactoryBot include:

  • Associations
  • Sequences
  • Aliases
  • Inheritance
  • Callbacks

Lesson 7 of 19
Last updated August 7, 2022