Before I jump in to saying how to write unit testing in Ruby on Rails, let me share what i felt about testing. When I was introduced about Unit Testing, I felt its simply a waste of time (IMHO I think many coders before getting addicted to testing might feel the same way), what is so great about testing if I can test my own code manually that’s what coders (people who are not aware of unit testing importance) might think so.
Initially I wasn’t writing any test cases and I started adding more and more features to my application. My application became big and I wasn’t able to test every pieces of my features manually. I made a minor change and it started breaking other few features, but I didn’t realize it until my colleague spotted it. It was easy to fix so I fixed but, some times it takes hours to fix a bug, bugs are invisible and invincible if you don’t write testcases, I made an innocent change over here, but it broke stuff way over somewhere, I am afraid to refactor or change my code now. So the moral of the stroy is “write test cases“.
Writing test cases is like drinking beer, it tastes bitter if you are new to it but it tastes great after your taste buds realizes it. Eventually you will get addicted to it. 😉 Many developers who realized the importance of testing became addicted to testing. They start writing code only when they had beer oops sorry I mean writing tests first.
Writing test cases in Ruby on Rails is as simple as shown below
[source language=”Ruby”]
class FirstTest < ActiveSupport::TestCase
def test_addition
assert(1 + 1 == 2, "Addition should work.")
end
def test_subtraction
assert(2 - 1 == 2) # should fail
end
end
[/source]
If you are using Netbeans, you can use short cut keys like shift+F6 or Ctrl + F6 to run the test.
Now, lets create a simple model in Rails, say Account (item:string, amount:decimal)
Account.rb
[source language=”Ruby”]
class Account < ActiveRecord::Base
validates_presence_of :item
validates_numericality_of :amount
end
[/source]
Now the test case for the about model would look something like below code.
Please see the inline comments for more info about the below test case.
account_test.rb
[source language=”Ruby”]
require ‘test_helper’
class AccountTest < ActiveSupport::TestCase
#loads fixtures from accounts.yml
fixtures :accounts
def test_should_create_account
assert_difference 'Account.count' do
account = create_account
assert !account.new_record?, "#{account.errors.full_messages.to_sentence}"
end
end
def test_should_require_account_item
assert_no_difference 'Account.count' do
account = create_account(:item => nil)
assert account.errors.on(:item)
end
end
def test_should_require_account_amount_numeric
assert_no_difference ‘Account.count’ do
account = create_account(:amount => ‘foo’)
assert account.errors.on(:amount)
end
end
#The below protected method creates an account record in the test database mentioned in database.yml
protected
def create_account(options = {})
record = Account.new({ :item => ‘Mouse’, :amount => 25.05 }.merge(options))
record.save
record
end
end
[/source]
Now lets see how the results would look like if I run the test case via Netbeans IDE.
BTW, there is limit on number of beers that one can drink and so number of test cases one can possibly write. I will soon write a blog about it with the help of some test coverage tools like rcov. I would be interested in hearing your comments as well.
I can’t agree more with your points on testing… I really didn’t understand how important they are until I started doing TDD. TDD has made me a better and faster programmer. Tests are VERY important.
My friend posted a really good blog post that made it very clear though a real-world analogy. http://app.arat.us/blog/?p=159
Great post! I’ll subscribe right now wth my feedreader software!