Factory Bot Rails Gem

Why Factory Bot?

From the world's most reliable resource Wikipedia:

Factory Bot is often used in testing Ruby on Rails applications; where it replaces Rails' built-in fixture mechanism. Rails' default setup uses a pre-populated database as test fixtures, which are global for the complete test suite. Factory Bot, on the other hand, allows developers to define a different setup for each test and thus helps to avoid dependencies within the test suite.

There is more info on the why on the Why Factories article.

This is simply a quick start to get up and going to test model validation.


  1. thoughtbot/factory_bot_rails
  2. thoughtbot/factory_bot
  3. Creating an Article model in Rails
  4. Testing RSpec
  5. Why Factories?

Quick start

rails new <project> -- api cd <project> gem install rspec factory_bot_rails

Update Gemfile config

In the Gemfile:

group :development, :test do gem 'factory_bot_rails', '~>6.0' gem 'rspec-rails', '>= 3.9.0' end

Run bundle install.

Automatic factory definition loading

From the docs:

By default, factory_bot_rails will automatically load factories defined in the following locations, relative to the root of the Rails project:

factories.rb test/factories.rb spec/factories.rb factories/*.rb test/factories/*.rb spec/factories/*.rb

If you want to, you can set custom configuration in config/application.rb or the appropraite env config.

config.factory_bot.definition_file_paths = ["custom/factories"]

This will cause factory_bot_rails to automatically load factories in custom/factories.rb and custom/factories/*.rb.


Add the following configuration to test/support/factory_bot.rb:

# test/support/factory_bot.rb require "factory_bot_rails" RSpec.configure do |config| config.include FactoryBot::Syntax::Methods end

Be sure to require that file in test/test_helper.rb:

# test/test_helper.rb ENV["RAILS_ENV"] ||= "test" require_relative "../config/environment" require_relative "./support/factory_bot" require "rails/test_help" require "rspec/rails" class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all # Add more helper methods to be used by all tests here... end

Create a model

From the guides, we are going to generate a new model.

rails generate model Article title:string text:text # run the migration rails db:migrate

If successful, the migration should return:

== CreateArticles: migrating ================================================== -- create_table(:articles) -> 0.0019s == CreateArticles: migrated (0.0020s) =========================================

Update Ruby

Update app/models/article.rb to look like the following:

class Article < ApplicationRecord validates :title, presence: true, length: {minimum: 5} validates :text, presence: true, length: {minimum: 5} end

Add the following to the factories directory

# test/factories/articles.rb FactoryBot.define do factory :article do title { "MyString" } text { "MyText" } end end

Add an Rspec for the model

# test/models/article_test.rb require "./test/test_helper" class ArticleTest < ActiveSupport::TestCase describe "article model" do before(:all) do @article1 = FactoryBot.create(:article) end it "is valid with valid attributes" do expect(@article1).to be_valid end it "is not valid without a title" do article2 = FactoryBot.build(:article, title: nil) expect(article2).to_not be_valid end it "is not valid without text" do article2 = FactoryBot.build(:article, text: nil) expect(article2).to_not be_valid end it "is not valid without a title of min length 5" do article2 = FactoryBot.build(:article, title: "Min") expect(article2).to_not be_valid end it "is not valid without text of min length 5" do article2 = FactoryBot.build(:article, text: "Min") expect(article2).to_not be_valid end end end

Running the test

rspec test/models/article_test.rb

We should get something like the following out:

..... Finished in 0.04765 seconds (files took 0.90722 seconds to load) 5 examples, 0 failures Run options: --seed 18801 # Running: Finished in 0.001607s, 0.0000 runs/s, 0.0000 assertions/s. 0 runs, 0 assertions, 0 failures, 0 errors, 0 skips