Re.Mark

My Life As A Blog

Ruby Tuesday #13 : Testing

with one comment

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.

When I started this series of Ruby Tuesdays, Matt recommended ZenTest, so I thought I’d look at that, too.  You can install it as a gem.  Once it’s installed, I called it with the following command:

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 Growlthis might be for you.

About these ads

Written by remark

July 8, 2008 at 7:05 pm

One Response

Subscribe to comments with RSS.

  1. I’d also suggest you look at acceptance testing [or executable specification] in Ruby. Have a look at my post on setting up the plain text story runner using rspec

    leftshift

    July 13, 2008 at 9:39 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: