Rspec Testing

7 Min. Read
Aug 7, 2019

Testing is a process to evaluate the functionality of a software application with an intent to find whether the developed software met the specified requirements or not. It is done to produce the defect free product.Generally, testing types involves Manual testing and Automation testing.

Manual testing is the act of testing the software frome the perspective of the client to ensure the product contains the required features or not and to ensure the application is working properly. On the other hand Automation testing involves writing the test script using the different automation tools. Rspec is one of the famous ruby testing tools whose idea is to test the behaviour rather than only method testing.


Configure the Rspec for model and controller Testing

Firstly a basic app is created : rails new ...

Add the rspec-rails gem in the gemfile inside the development and test block

1
2
3
  group :development, :test do
    gem 'rspec-rails', '~> 3.8'
  end

Then run rails g rspec:install in the console This generates the two files spec_helper.rb , rails_helper.rb. Rails helper is used to extend the functionality of spec. Spec helper is used for writing any configuration file for Rspec.


To test User Model

In the console, type rails g rspec:model user It will create user_spec.rb under the spec folder in the model folder.

Here, we will test the User model’s validation and scope

1
2
3
4
5
6
7
8
9
10
11
require 'rails_helper'
RSpec.describe User, type: :model do
 context 'validation test' do
  it ""
  it ""
 end
 context 'scope test' do
  it ""
  it ""
 end
end

In order to run test we need the object dataset.For this, Factorybot is used which can be installed as :

Add the gem 'factory_bot_rails' to Gemfile:

and run bundle install from your shell. Then 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.

1
2
3
4
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

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

The next library that is required is Faker. It is useful in generating the fake data. It can be installed as

gem install faker

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. In our factories file, we will add a user factory like this,

1
2
3
4
5
6
7
8
FactoryBot.define do
  factory :user do
    first_name {Faker::Name.first_name }
    last_name {Faker::Name.last_name }
    email {Faker::Internet.email}
    password {Faker::Internet.password}
  end
end

Since we are testing the User’s attribute validation, we need to write the validation in User model (app/model/User.rb).

1
2
3
  class User < ApplicationRecord
    validates :first_name, :last_name, :email, :password,  presence: true
  end

Now, we can start writing factories for our class and write test

In the user_spec.rb under the spec folder in the model folder. “`ruby require ‘rails_helper’

RSpec.describe User, type: :model do context ‘validation test’ do it "ensures first name presence” do let(:user) { create :user expect (user). to eq(true) } end end end “` Above, ‘describe’ is the keyword which wraps up all the sets of the test whereas

‘context’ is the keyword which specifies the name of the test to be carried out,

‘it’ keyword contains the single set of test.‘let’ contains the user object which will run only when called upon.

The user_spec.rb is run in the terminal. And the test will be pass as the user all dataset is created.

Similarly, we are going to test scope of the User model. Add the following code in the User model

1
2
3
4
5
 class User < ApplicationRecord
  scope :active_users,-> {where (active:true)}
  scope :inactive_users,-> {where (active:false)}
  validates :first_name, :last_name, :email, :password,  presence: true
end

The corresponding test for the scope test can be as follows :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require 'rails_helper'
  RSpec.describe User, type: :model do
   context 'scope test' do
    let(:params) {{first_name: 'First', last_name: 'Last', email: '[email protected]'}}
     before(:each) do
     create :user , params.merge(active: 'false')
     create :user , params.merge(active: 'false')
     create :user , params.merge(active: 'true')
    end
  it 'should return active users' do
   expect(User.inactive_users.size). to eq(2)
  end
 end
end

In the above code, before method take a symbol indicating the scope, and a block of code to execute.before(:each) blocks are run before each example. let holds the variable which contains the attribute for user.

To test Controller


Firstly, the controller spec file is generated by rails g rspec:controller users. The RESTFUL methods as index, show, new, create, update, delete can be tested along with the respective http verb.

GET request:

Tests for GET request of an index and new methods can be very simple as, checking the number of objects contained in the index page. For show operations, an object is created using Factorybot and passed along the parameter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
require 'rails_helper'
 RSpec.describe UsersController, type: :controller do
  context 'GET #index' do
  it "assigns @user" do
  user = create :user
  get :index
  expect(assigns(:user)).to eq([user])
  end
  it "renders the index template" do
  get :index
  expect (response).to render_template("index")
  end
 end
end

In the above example inside the it block the user object is created and is assigned to the user variable, the next line defines the GET http verb along with it’s respective index method. Variable instantiated by the controller method is evaluated using the assigns(:variable name). The test is expected to pass if the requested object matches the the value inside the created user objects.

1
2
3
4
5
6
7
8
9
10
require 'rails_helper'
 RSpec.describe UsersController, type: :controller do
  context 'GET #show' do
  let!(:user) { create :user}
   it 'should success and render to edit page' do
   get :show, params: { id: user.id }
   expect(response).to have_http_status(200)
  end
 end
end

The above example is the test for the show method where the user is generated. The show method is invoked with the params hash of user id. The test is said to be passed if the response after the request is said to be positive.

POST request:

The post request for create operation can be checked by an increment in the object count.

1
2
3
4
5
6
7
8
9
10
11
context 'POST #create' do
 let!(:user)
  it 'create a new product' do
   params = {
   name: 'Ram',
   age: 50
  }
  expect { post(:create, params: { user: params }) }.to change(User, :count).by(1)
  expect(flash[:notice]).to eq 'User was successfully created.'
 end
end

PUT request:

The update function uses the put request, where the object is first created using Factorybot. The values of the object are then updated by a local variable. The test is then verified by reloading the object and checking its field values from the local variable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
context 'PUT #update' do
 let!(:user) { create :user }
  it 'should update user info' do
   params = {
   name: 'Hari',
   age: 45
   }
   put :update, params: { id: user.id, user: params }
   user.reload
   params.keys.each do |key|
   expect(user.attributes[key.to_s]).to eq params[key]
   end
 end
end

DELETE request:

The delete request takes the object to be deleted as a parameter and it can be tested by a decrement in object count.

1
2
3
4
5
6
7
context 'DELETE #destroy' do
  let!(:user) { create :user }
    it 'should delete product' do
    expect { delete :destroy, params: { id: user.id } }.to change(User, :count).by(-1)
    expect(flash[:notice]).to eq 'User was successfully deleted.'
  end
end