The testing stage is a very important step in the software development life-cycle of any application. It helps software developers detect and fix bugs much earlier in the development process.
This short presentation will use a couple of ruby gems to help in the testing process. The gems are rspec-rails, shoulda-matchers and factory_bot_rails. Lets first take a look at what each gem does.
Before we write any code, here are the requirements for completing this short tutorial. You should install ruby 2.6.5 or greater and rails 5 or above. Now let us begin.
Open the Gemfile, which is in the root directory of your project. We are going to add the rspec-rails file in the :development and :test group
group :development, :test do
gem 'rspec-rails', '~> 4.0.0'
end
run
bundle instal
l in your terminalthen run
rails generate rspec:install
This generates the required files to run rspec. We’ll install the second gem shoulda-matchers in the :development and :test group
group :development, :test do
gem 'shoulda-matchers’
end
then run
bundle install
Go to the spec folder in your project root directory. Open the rails_helper.rb file. Paste the following code at the bottom of the file:
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
Finally, we are going to install our last gem factory_bot_rails in the :development and :test group
group :development, :test do
gem 'factory_bot_rails', '~> 5.2'
end
then run bundle install. The factory_bot_rails gem requires some additional configuration. Go to the spec folder and create a support folder inside it. Then create a factory_bot.rb file inside the support folder. Paste the following code inside the file.
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
In the spec/rails_helper.rb file add the following:
require './spec/support/factory_bot.rb'
We’ll create two models for this project; a user and a post. Let us start with a user. Run the following command to create a user.
rails generate model User name
You can check the user.rb file in the models folder.
We will put a validates :name, presence: true and the has_many :posts. The has_many :posts indicates that the user has a one to many relationships with the post and the validates ensures that no null value can be saved on the column name
By now, your model should look like:
class User < ApplicationRecord
has_many :posts
validates :name, presence: true
end
Next, we will create a post. A user can create many posts and a post can only be created by one user. That means that the post has a foreign key in its table that belongs to the user. We will create the post model.
Run
rails generate model Post content:text user:references
. The user:references creates a foreign key called user_id on the post table. This user_id column is the primary key to the user table. Then run
rails db:migrate
.In the app/models/post.rb you will notice, that there is a belongs_to :user line of code, meaning that a post can only be created by one user. You can add the validates :content, presence: true just below the belongs_to :user
You post model should look like:
class Post < ApplicationRecord
belongs_to :user
validates :content, presence: true
end
Navigate to the spec folder and you will notice that you have a folder created called factories. Inside the factories folder, there is a user.rb. The user.rb in the factories folder has a name with data inside the brackets. If you haven’t noticed, this is the column that belongs to the user in the database. If you head over to the db/schema.rb file you will see that column in the schema. Likewise for the post. The user { nil } row that you see on the spec/factories/post.rb is the foreign key in the post table that links it to the user table.
Now that we have set up our models, let us write some tests. Go to the spec/models/user.rb file and open it. We are going to test for 3 scenarios in our models. We are going to test the user relationship to the post, test that a null value can’t be saved in the name column, and if we can save a user to the database. The shoulda-matchers and factory_bot_rails gems will make our work a lot easier.
Let us write the tests for our user model. Your User model should resemble:
require 'rails_helper'
RSpec.describe User, type: :model do
describe 'User Associations' do
it { should have_many(:posts) }
end
describe 'Validation Tests for User' do
let(:user) { build(:user) }
it 'should validate user name' do
user.name = nil
expect(user.save).to eq(false)
end
end
describe 'Create User' do
let(:user) { build(:user) }
it 'should save user' do
expect(user.save).to eq(true)
end
end
end
The should have_many keywords are from shoulda-matchers gem. They help in testing the relationships. The build(:user) creates a user instance using factory_bot_rails.
Type
rspec spec/models/user_spec.rb
in your terminal. All the 3 test cases should pass.Let us handle the test cases for our Post model.
Write the following code in your Post model:
require 'rails_helper'
RSpec.describe Post, type: :model do
describe 'Post Associations' do
it { should belong_to(:user) }
end
describe 'Validation Tes ts for Post' do
let(:user) { create(:user) }
let(:post) { attributes_for(:post) }
it 'should validate post content' do
post_test = user.posts.build(post)
post_test.content = nil
expect(post_test.save).to eq(false)
end
end
describe 'Create Post' do
let(:user) { create(:user) }
let(:post) { attributes_for(:post) }
it 'should save user' do
post_test = user.posts.build(post)
expect(post_test.save).to eq(true)
end
end
end
The let(:post) { attributes_for(:post) } allows us to pass the post attributes in form of a hash. This enables us to pass the post in the user.posts.build(post).
Since the post has a many to one relationship with the user, we use post_test = user.posts.build(post). This means that for a post or posts to be created there has to be a user.
Now run
rspec spec/models/post_spec.rb
. All the 6 test cases should pass. To run all the test cases just type rspec. And that's it! With this, you can build on your knowledge on how to write rspec test cases.