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.
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