Ruby Tuesday #13 : Testing
Having completed a rudimentary Twitter client, I thought it was high time I figured out how unit testing works in Ruby. The good news is that there’s a framework (called Test::Unit) distributed with Ruby. To create a class of tests, simply create a new class and inherit from Test::Unit::TestCase. Any method in the class that begin with test will be executed as tests. Here’s a simple test for the translator in my Twitter client:
require 'test/unit' require 'Twitter' require 'rexml/document' include REXML class Test_Translator < Test::Unit::TestCase def test_element_to_user xml = '<user> <id>99999999</id> <name>Username</name> <screen_name>Screen Name</screen_name> <location>Location</location> <description>Description</description> <profile_image_url>image_url</profile_image_url> <url>url</url> <protected>false</protected> <followers_count>404</followers_count> </user>' translator = Translator.new element = get_user_element(xml) user = translator.element_to_user(element) assert_equal('99999999', user.id) assert_equal('Username', user.name) assert_equal('Screen Name', user.screen_name) assert_equal('Location', user.location) assert_equal('Description', user.description) assert_equal('image_url', user.image_url) assert_equal('url', user.url) assert_equal('false', user.protected) assert_equal('404', user.followers_count) end private def get_user_element(xml) xml_document = Document.new(xml) xml_document.root end end
Run that test and it tells me there are 8 assertions in 1 test. And there’s an error. The error is a NoMethodError – tells me that there is no method followers_count on the User instance. And looking at the class it’s clear why:
class User attr_reader :id, :name, :screen_name, :location, :description, :image_url, :url, :protected def initialize(id, name, screen_name, location, description, image_url, url, protected, followers_count) @id = id @name = name @screen_name = screen_name @location = location @description = description @image_url = image_url @url = url @protected = protected @followers_count = followers_count end end
There’s an instance variable that gets set when an instance is created, but there’s no property defined. All that’s needed is to update the first line of the class like so:
attr_reader :id, :name, :screen_name, :location, :description, :image_url, :url, :protected, :followers_count
And the test passes. Lots more to learn in Test::Unit, but that feels like a good start.
zentest Twitter.rb >Test_Twitter.rb
That creates a file called Test_Twitter.rb that contains tests for the methods in Twitter.rb. Here’s a brief excerpt:
class TestClient < Test::Unit::TestCase def test_download_friends_timeline raise NotImplementedError, 'Need to write test_download_friends_timeline' end
As you can see, for each method an error is raised to prompt you to write the test code. There’s some other goodness in there like the autotest daemon that automatically runs your tests as you make changes. And if you like to have your tests running automatically and you use Growl – this might be for you.