DEV Community

Danny Tseng
Danny Tseng

Posted on

Unit testing with RSpec - Model Spec

In one of my previous blog posts, I wrote about testing with RSpec and some of the testing practices and what their corresponding specs are. I focused in particular on the Request Spec which is the spec that is used for testing controller actions such as the routes and end-points. For this post I want to talk about a testing technique that is known as unit testing in Test Driven Development and the tools that you can use to perform such test.

Just a quick refresher, RSpec is a tool that can be utilized in Ruby applications to test the various aspect of said applications from model, view, to controllers individually or in conjunction. RSpec is also a Ruby gem. In order to include RSpec in your application, simply add "rspec-rails" gem in the gem file and run bundle install. After that, you will have access to RSpec and you can begin writing test suite for your application.

Unit testing is a testing technique that is used to test different parts of the application in isolation. A unit in this case is usually the smallest part of the application. In the case of the MVC design pattern, the unit testing will be applied to the M which is the model part of the application because model is usually the baseline of the application and other features and functionalities usually involves the use of models.

To begin uniting testing on the models, we can utilize the Model Spec for testing models. In the terminal, simply type the line below.

rails g rspec:model user

"Model" in this command simply indicates that this is a model spec and the word that follows is the name of the model which in this case is user. This command is going to generate a spec folder with a models folder inside it. The user spec file will be inside the models folder. Inside the model spec file for user, you will see some code inside the file such as below.

RSpec.describe User, type: :model do


end

Within the do-end block is where you will be able to add test code for context and examples to verify the different valid or invalid attributes for model creation. The "describe" keyword creates an example group that contains a collection of related tests. Another keyword "context" is pretty much the alias for "describe" where it will also create an example group, however, "context" cannot be the top-level method. It is valid to nested describe and context within each other. Just keep in mind that the most outer method cannot be "context."

When I was working on the model spec for one of my projects, I created an example group for testing validations.

RSpec.describe User, type: :model do

  context 'validation test' do

  end
end

In my user class, I have included some active record validations and one of them states first name needs to be present.

class User < ApplicationRecord
    has_secure_password
    validates :first_name, presence: true
    validates :last_name, presence: true
    validates :email, presence: true
    validates :username, uniqueness: { case_sensitive: false }, presence: true

end

To validate the presence of first name, I include a test example for that. An example in this case is the it-end block which takes a string for describing what this particular test or example does.

RSpec.describe User, type: :model do

  context 'validation test' do
    it 'ensures first name presence' do
      user = User.new(last_name: 'last', username: 'username', password: '123', email: 'sample@example.com').save
      expect(user).to eq(false)
    end
end

What the code inside the it-end block above does is to try to create an user object without a first name attribute provided. There is a .save at the end of the .new() which will return true or false if the object is valid and can be saved to the database. The expected outcome for this operation is false hence "expect(user).to eq(false)." When you run rspec in the terminal, you should see this particular test appears in green which means the outcome is as expected. If this particular test appears in red, there will be error messages appear as well so you will be able to know what exactly is wrong. One possible cause for the error is the object is created successfully which means that the first name presence is not enforced properly. This is one example of how we can utilize model spec to help us figure out if the models are implemented properly and the behaviors are as expected.

Other than testing the presence of first name, you can also repeat the same process for last name, email, or other information that you want to be present when creating objects. For testing uniqueness of the username, one can create two user objects with the same user name and test if the second user can be created properly. These are some of the things that model spec can be used for performing unit testing on different models.

Conclusion
Unit testing is an important part of Test Driven Development because it ensures the smallest testable parts of the application to be working properly. This is also an integral part for other testing techniques such as feature testing, or integration testing where the use of models and classes are needed in these tests that there may be some undesired or unexpected outcome if the smallest units of the application are not working as intended.

References:
http://softwaretestingfundamentals.com/unit-testing/
https://pragmacoders.com/blog/testing-with-rspec
https://www.youtube.com/watch?v=71eKcNxwxVY

Top comments (0)