Getting to Know the Ruby Standard Library – MiniTest

Ghetto or not, if you want to use or contribute to the ruby standard library, getting to know the source is essential. We will look at one of the libraries everyone should be acquainted with, test/unit. There are dozens of testing frameworks in ruby, but this is the one you know everyone will have available. I’ll assume you’re using ruby 1.9.x, because it’s awesome.


Test/Unit is a ruby implementation of original xUnit architecture. In general you write your tests by extending Test::Unit::TestCase, adding methods that look like test_*something*, and then you can run that file directly with ruby my_neat_test.rb. Since it’s best to have a purpose when learning, we’ll try to answer two questions:


To get started, open up Test/Unit (qw test if you have Qwandry installed).

Looking at unit.rb we immediately see something odd:

# test/unit compatibility layer using minitest.
require 'minitest/unit'
require 'test/unit/assertions'
require 'test/unit/testcase'

In ruby 1.9 minitest was swapped in to replace test/unit. The code in test/unit is just here to make sure all the tests behave the same way in ruby 1.9 as they did in ruby 1.8. If you scroll down to the bottom of unit.rb, you will find this:


This is going to get called any time that you require test/unit, so lets find out what it does, and I suspect we can unravel our first question.


There isn’t much in test/unit so lets take a look at minitest since that’s what ruby 1.9.x is really using (qw minitest). Since we saw that autorun is called whenever we require test/unit, autorun.rb sounds like a good place to start looking. The contents of this file?


Ok, well we have three more files left, so unit.rb is probably another good place to look. A quick search for autorun will yield:

class Unit
  def self.autorun
    at_exit {
      next if $! # don't run if there was an exception
      exit_code =
      exit false if exit_code && exit_code != 0
    } unless @@installed_at_exit
    @@installed_at_exit = true

We see that at_exit is being called. If you haven’t run across this before, so a quick peak at the docs for ruby-core shows that this block will be executed right before ruby exits. Notice that minitest calls inside the block? Now you know how the tests get run. You can also see that @@installed_at_exit is in there to prevent your tests from being launched more than once. Neat stuff, one question down.

Next up, how does it know which tests to run? We saw that is going to get called, so that’s a good place to start.

def run args = []
  @verbose = args.delete('-v')

  filter = if args.first =~ /^(-n|--name)$/ then
             arg = args.shift
             arg =~ /\/(.*)\// ?$1) : arg
             /./ # anything - ^test_ already filtered by #tests

We can see that this code starts out by using the options from ARGV to configure MiniTest::Unit. Let’s look at filter it will either end up being the name of a test, or a regexp that matches everything. The comment looks promising too. Hopping down a few lines we see that filter gets used:

run_test_suites filter

Looking ahead we see that TestCase.test_suites seems to be enumerable, and each suite has a set of test methods.

def run_test_suites filter = /./
  TestCase.test_suites.each do |suite|
    suite.test_methods.grep(filter).each do |test|
      inst = test

We’ll ignore the test_suites for now and look into the test_methods code, this is probably where minitest finds all of the tests you wrote.

def self.test_methods
  methods = public_instance_methods(true).grep(/^test/).map { |m|

And there we go, your test inherits from TestCase and TestCase.test_methods introspects on itself looking for all the public methods that start with the word test. So now we’ve answered our questions, and if you were paying attention, we learned a few things that might be useful.


In ruby 1.9 test/unit was replaced with minitest. It turns out that minitest registers an at_exit hook, and that it introspects on its own methods to figure out what to run. Now while you were in the code, perhaps you noticed few other interesting things that might be of use later:

Now aren’t you glad you took a moment to look at the standard library? Go forth and do something great.

blog comments powered by Disqus
Monkey Small Crow Small