2. Introducing Test/Unit

2.1. The Small Picture

2.1.1. Hello World

As we all know, Ruby ships with a boat load of great libraries. If you're like me, you've only used a quarter of them or so. One little gem of a library is test/unit. It comes packaged with Ruby 1.8.1, so there's nothing to download.

By using one line of code require 'test/unit', you arm your Ruby script with the capability to write tests.

Let's show you a really basic test, and then we'll step through it and explain some details.

# hello_test.rb

require 'test/unit'

class HelloTestCase < Test::Unit::TestCase
  def test_hello
    assert true
  end
end

Quite possibly the simplest and least useful test ever invented, but it shows you the bare bones of writing a test case. That script can be run from the command line the same way your run any other Ruby script.

Simply run ruby hello_test.rb and you will see the following:

Started
.
Finished in 0.0 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

Congratulations, your first test.

2.1.2. What Does It All Mean?

By looking at the output of a test, you will be able to tell if the tests pass or not. In our example, not surprisingly, we've passed. The summary shows 1 test, 1 assertion, 0 failures, and 0 errors.

So, let's break our test source code down.

First, line 1.

require 'test/unit'

You'll always have this when writing unit tests. It contains the classes and functionality to write and run unit tests.

Next, we have a class HelloTestCase which derives from Test::Unit::TestCase.

class HelloTestCase < Test::Unit::TestCase

All of the tests that you create will directly subclass Test::Unit::TestCase. The TestCase provides the “housing” of where your tests will live. More on this in a bit.

Finally, we have a method called test_hello.

def test_hello

All tests must follow this naming convention: their names start with the first 4 characters test, as in test_hello, testme, and testarosa. If you create a method that doesn't start with test, the testing framework won't recognize it as a test, hence, won't run it automatically, hence it is a normal Ruby method.

Inside our test_hello method, we have an assertion.

assert true

Assertions are where the real work gets done. There are a whole army of different types of assertions that you'll use to make sure your code is doing the right thing.

2.2. The Big Picture

Grab a cup of coffee and dunk your head in some ice water, because here's some more theory.

There are 4 major players in the testing game.

2.2.1. A: The Assertion

An Assertion is 1 line of code that evaluates an object (or expression) for expected results.

For example, is this value = that value? is this object nil? does this line of code throw an exception? is the user's password greater than 5 characters?

2.2.2. B: The Test

A Test is method that contains assertions which represent a particular testing scenario.

For example, we may have a test method called test_valid_password. In order for this test to pass, we might need to check a few things:

  • password is 4 or more characters

  • password isn't the word ‘password'

  • password isn't all spaces

If all of these assertions are successful, the test will pass.

2.2.3. C: The Test Case

A Test Case is a class inherited from Test::Unit::TestCase containing a testing “strategy” comprised of contextually related tests.

For example, I may have a test case called UserTestCase which has a bunch of tests that check that:

  • the password is valid (test_password)

  • the username doesn't have any forbidden words (test_username_cussin)

  • a user is under the age of 150 (test_shriveled_raisin)

2.2.4. D: The Test Suite

A Test Suite is a collection of test cases. When you run a test suite, it will, in turn, execute each test that belongs to it.

For example, instead of running each test unit individually, you can run them all by creating a suite and including them. This is good for stuff like continuous-build integration.

We won't get into test suites in this article.

2.2.5. The Hierarchy

The relationship of these objects to one-another looks like this:

  • a test suite

  • has many test cases

  • which have many tests

  • which have many assertions