Test-driven development with Rails with a simple example

May 15, 2019
Tanzina

Writing test codes are often tedious. It feels like I am wasting my valuable time.

This is how I used to think about writing test codes.

I came to know – to be honest, got bound to know -about the advantage of writing test codes when my project grew bigger. Whenever I changed my codes in one place of my project, it broke the code in several other places about which I did not have any idea!

Then I realized that if I had written test codes from the beginning of my project, it would have saved a huge amount of my time and effort in the long run.

One of the best approaches for ensuring high test coverage in rails project is to follow the Test Driven Development (TDD) methodology. In this article, I will give a simple idea about what TDD is. Besides, I will provide a simple example of implementing it in a Rails application.

What is Test Driven Development (TDD)

TDD or Test Driven Development is a key practice of extreme programming in which the developer writes the test code before writing the actual code. Then the developer writes the actual codes to pass the test codes. And finally, the developer refactors the code to maintain overall code quality.

Steps of TDD

According to the definition of TDD, a developer can follow the following steps to successfully write test codes –

1) Write test codes initially
2) The test code will fail as there is no implementation yet.
3) Re-write codes to make the test codes pass.
4) Run all the old test codes and ensure that they are also passing.
5) Refactor the codes to maintain code quality
6) Repeat

A simple example of implementing TDD in Rails application

I am going to provide a basic example of implementing TDD in a rails application.

TDD on Rails

Add Rspec to your Gemfile for development and test environment –

Gemfile

 group :test, :development do
gem 'rspec-rails', '~> 3.4.2'
gem 'factory_girl_rails', '~> 4.7.0'
end

In addition to Rspec, we have used factory girl. The ‘factory girl’ will be used instead of the default fixture of Rails.

Run the following in your command line –

bundle install
bundle exec rails generate rspec:install

Now let’s do TDD!

There are three models in our Demo Rails application. They are Lesson, User, and Subscription.

app/models/lesson.rb

class Lesson < ActiveRecord::Base
end

app/models/user.rb

class User < ActiveRecord::Base
has_one :subscription
end

app/models/subscription.rb

class Subscription < ActiveRecord::Base
belongs_to :user
end

A user may or may not have a subscription. If a user has subscription only then the lesson will be visible to the user.

I will have to write a function in the Lesson model that will take the user object as a parameter. This function will return true if the user has a subscription. Otherwise, the function will return false or nil.

In the normal development process, we would have written that simple method ‘visible_by?’ in the Lesson model. However, as we are doing TDD, we will write the test code first.

However, before writing the test code, we will have to set up the factory girl to generate the test fixtures for testing. We will have to create test fixtures for subscription, user, and lesson to write the test code.

spec/factories/subscriptions.rb

 FactoryGirl.define do
factory :subscription do
user_id 1
end
end

spec/factories/users.rb

 FactoryGirl.define do
factory :user do
first_name "test"
last_name "test"
email "test@example.com"
end
end

spec/factories/lessons.rb

 FactoryGirl.define do
factory :lesson do
position 1
title "Test Lesson"
end
end

Okay, now we are ready to write our test code.

spec/models/lesson_spec.rb

describe Lesson do

let(:subscription) { FactoryGirl.create(:subscription) }
let(:user) { FactoryGirl.create(:user, :subscription) }
let(:lesson) { FactoryGirl.create(:lesson) }

it 'should be visible by user who have subscription' do
expect(lesson.viewable_by?(user)).to be_truthy
end

end

Now if we run the test code, it will obviously fail as we have not written the function ‘viewable_by?’ yet.

Now we have to write the function on Lesson model.

app/models/lesson.rb

class Lesson < ActiveRecord::Base
def viewable_by?(user)
if user.subscription.present?
return true
else
return false
end
end
end

Now if we run the test, this will pass.

However, we may refactor the code to make it cleaner and more readable by modifying the function in the following way –

app/models/lesson.rb

class Lesson < ActiveRecord::Base
def viewable_by?(user)
return true if user.subscription.present?
end
end

Now if we rerun the test code, it will pass. Besides, the code is more readable now.

This is an elementary example of writing test codes according to TDD in a rails project. Here we wrote the test code first. Then we ran it, and it failed. After that, we wrote the actual code to make the test code pass. Finally, we refactored the code to make it more readable.

Conclusion

Writing test code is crucial in big projects. This saves a lot of time as well as money of the project owner. In a big rails project, we should try to follow the test driven development approach as it will reduce bug as well as improve overall project structure and code quality.

Contributor: Khaled Imran, Nascenia

No comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.