[This is the 4th part of a series of posts about writing a Ruby gem. The introductory post about this tutorial contains links to each part of the tutorial. Previous post - Publishing to Rubygems.org.]

So far in this tutorial we haven’t written any code that would be useful in solving Sudoku. The reason is that I didn’t want to start writing any code until we have a test framework set up for testing our code.

Test::Unit is the unit testing framework that ships with Ruby, so we will first set up our gem to run unit tests with the “rake test” command. However, I prefer another testing framework, Rspec, for writing the tests. (We'll set up Rspec in the next part of the tutorial and then continue using that rather than Test::Unit for testing.)

We will write a simple method in the sudoku module that will return a string “Sudoku: version 0.0.0” (the version number will obviously have to be taken from lib/sudoku/version.rb).

We will put all our unit tests in a directory called test. We will now add a rake task called “test” to run all the unit tests. To create this, we will first need to create a Rakefile that looks like this:

require 'rake/testtask'

Rake::TestTask.new do |t|
 t.libs << 'test'
end

desc "Run tests"
task :default => :test

Rake already provides a task called test, so we are making use of that and have configured the task to use the test/ directory with t.libs << 'test'. We will also configure rake to make the test task the default when rake is run. Running “rake” without a task name would now be the same as running "rake test". (In the next post, we'll change this to run our Rspec specs rather than the unit tests.)

Now let’s add a test file test/test_sudoku.rb and add a silly test that we know will fail.

require 'test/unit'
require 'sudoku'

class TestSudoku < Test::Unit::TestCase
  def test_silly_example
    assert_equal 2+2, 5
  end
end

2+2 isn’t equal to 5, so this test should fail. Run the rake task:

$ rake test
Loaded suite /home/nithin/.rvm/gems/ruby-1.9.2-p180/gems/rake-0.9.2/lib/rake/rake_test_loader
Started
F
Finished in 0.000950 seconds.

 1) Failure:
test_silly_example(TestSudoku) [/home/nithin/work/sudoku/test/test_sudoku.rb:7]:
<4> expected but was <5>.

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

Test run options: --seed 21001
rake aborted!
Command failed with status (1): [/home/nithin/.rvm/rubies/ruby-1.9.2-p180/b...]

Tasks: TOP => test
(See full trace by running task with --trace)

Now change the assertion to make the the test pass.

$ rake test
Loaded suite /home/user/.rvm/gems/ruby-1.9.2-p180/gems/rake-0.9.2/lib/rake/rake_test_loader
Started
.
Finished in 0.000544 seconds.

1 tests, 1 assertions, 0 failures, 0 errors, 0 skips

Test run options: --seed 23369

If you try running rake without the task name, you will see that the output is exactly the same.

Now let’s remove the silly test and write a test that acually tests the version_string method that we’re adding.

  def test_version_string
    assert_equal Sudoku.version_string, "Sudoku version #{Sudoku::VERSION}"
  end

Now if you run rake you will get an error with the message: “NameError: uninitialized constant TestSudoku::Sudoku”. To fix this, we need to add the code for the version_string method in lib/sudoku.rb.

require 'sudoku/version'

module Sudoku
  def self.version_string
    "Sudoku version #{Sudoku::VERSION}"
  end
end

Now rake will run the test successfully. Let’s rebuild our gem and install it with the generated sudoku-0.0.0.gem file to see that it installs correctly.

However, we’re not done yet. If you check the gem directory in the gem installation path, you will see that our test/ directory is missing. To tell rubygems to include that code in the package, we’ll add the following line in the gemspec:

Gem::Specification.new do |s|
  # other stuff
  s.test_files  = Dir.glob("test/**/*.rb")
end

Rebuild and install the gem again and you’ll see the test directory in the installed gem path.

In the next part of the tutorial we’ll set up rspec for testing the gem and along with that start adding some real code for the sudoku solver.

[Subscribe to this blog to find out when the next part of this tutorial is published, or keep an eye on the first post in this series where I'll post the links to all published posts.]