Setting up Rspec and Factory Bot

Now that I know the basics of TDD and how to test my React front end applications, I wanted to work on testing my Rails API. With RSpec and Factory Bot it is possible to test your APIs quickly and easily, and to test how your API serves data from the database.

Setting up RSpec

To set up RSpec for our Rails application we need to make sure we install the Rails RSpec gem. This gem is specifically created to test Ruby and Rails applications. To install the gem you can add this code to your gem file and run bundle install,

group :development, :test do
gem ‘rspec-rails’, ‘~> 3.6’
end

After running bundle install you will need to run a Rails command to create a couple files. Run this code in your terminal,

rails generate rspec:install

This will create a spec folder which will contain a spec_helper.rb, a rails_helper.rb. An .rspec file will also be created in the root directory which will allow you to automatically require the spec helper in all specs, and allow you to enable color in your test outputs through these two lines,

app/.spec
--color
--require spec_helper

Now that we have these files we can begin writing our tests. The way we will structure our spec directory is that each type of spec will get its own folder. Example types are model, controller, request, or feature specs. For our example lets just create a simple User model and add some specs for that model.

We will create a folder for our model specs in the spec folder and then create a user_specs.rb file. Now that we have that set up theres on more gem that will making testing easier. We’ll install Factory Bot to create dummy data for our tests to use.

Setting up Factory Bot (formerly Factory Girl)

In order to effectively test our API we are going to need to stub in some data and user instances. To do this we will use the Factory Bot gem which allows the developer to set default values for the instances of our class that we create. The methods Factory Bot provides are create, build, attributes_for, and build_stubbed. The two most important are the create and build. Create will make a user instance and save it into the database. Build will make a user instance, but will not save it into the database. So to get started lets add the gem to our gemfile,

Gemfile
group :development, :test do
gem ‘factory_bot_rails’
end

Then, run bundle install and the gem will be added to your project. With the gem in place we can add a support folder within our spec directory with a factory_bot.rb file. This file will be responsible for configuring our factories to be used in the specs. The code looks like this,

app/spec/support/factory_bot.rb
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end

We then require this in our rails_helper.rb that was created earlier.

app/spec/rails_helper.rb
require 'support/factory_bot'

With all this in place we can begin writing factories for our classes and writing tests. Before we write a test for our user model lets first create a factory for it. We will create a factories.rb file in our spec folder, and within that folder we will define all our factories. When we run our tests the factories will be loaded in to our rails helper. For our simple user lets say they just have an email a username and a password. We will make sure that the email and the password are unique, and validate that all must be present. In our factories file we will add a user factory like this,

app/spec/factories.rb
FactoryBot.define do

factory :user do
username "Joe"
email "joe@gmail.com"
password "blah"
end
end

Now whenever we call on our factory these values will be used for our user. We can also override these default values and pass the desired attributes to the factory when we call on it. It would look like this,

# default call to factory
user1 = create(:user)
#user1 attributes will be username: Joe, email: joe@gmail.com, #password: blah
# override default arguments
user2 = create(:user, username: "Bob", email: "bob@gmail.com")
#user2 attributes will be username: Bob, email: bob@gmail.com, #password: blah

So now lets write our tests. We will test to make sure we can create a user with the factory, then make sure the validations are working correctly. We will use our factory to help us create users and test the validations. Here is what the tests will be,

app/spec/models/user_spec.rb
require "rails_helper"
RSpec.describe User, :type => :model do

before(:all) do
@user1 = create(:user)
end

it "is valid with valid attributes" do
expect(@user1).to be_valid
end

it "has a unique username" do
user2 = build(:user, email: "bob@gmail.com")
expect(user2).to_not be_valid
end

it "has a unique email" do
user2 = build(:user, username: "Bob")
expect(user2).to_not be_valid
end

it "is not valid without a password" do
user2 = build(:user, password: nil)
expect(user2).to_not be_valid
end

it "is not valid without a username" do
user2 = build(:user, username: nil)
expect(user2).to_not be_valid
end

it "is not valid without an email" do
user2 = build(:user, email: nil)
expect(user2).to_not be_valid
end
end

We set a before all statement just to make one base user in the database, so that we can test if our second user is valid. For our uniqueness tests we are checking that if we create another user that has the same username or email, it won’t be valid. When we test if a user is valid without one of the attributes, we explicitly pass nil to the factory for the attribute. Now that we have our tests and they are failing lets write our user model to pass the tests.

app/models/user.rb
class User < ApplicationRecord
has_secure_password
validates :username, uniqueness: true
validates :email, uniqueness: true
end

With this simple user class all of our tests are passing.

Summary

Overall with RSpec set up and our Factory Bot in place, we can write many different tests for our Ruby and Rails projects. RSpec provides an easy API to write assertions for our tests, while Factory Bot allows us to create stubbed in data for our tests. Both of these libraries are very helpful for testing more complex things, such receiving the correct responses from HTTP requests. I hope this helped you set up and learn some basic testing with RSpec and Factory Bot!

Sources: