MonkeySpecDoc: Specdoc output for Ruby's Test::Unit and Shoulda
For my work on RDTN, I did test-driven development (TDD) — although I admit that there is room for improvement in respect to strictness — and also tried out two frameworks for what they call behavior-driven development (BDD): RSpec and Shoulda. While I found it easier to work with Shoulda as a whole, I really like the output formatting options RSpec gives you, especially the specdoc format. So wanted to have this format even when I’m using Shoulda.
For example, let’s assume we have Shoulda tests for a HelloWorld program (you might call this obsessive-compulsive development). The tests look like this:
class TestHelloWorld < Test::Unit::TestCase
context 'HelloWorld' do
setup do
@hello = HelloWorld.new
end
should 'say "Hello, World!"' do
sio = StringIO.new
@hello.say_hello(sio)
assert_equal 'Hello, World!', sio.string
end
end
end
Let us further assume that we have an implementation that has an error, e.g. the exclamation mark is missing. So, running this with the runner from Test::Unit, we get the following message:
Loaded suite examples/helloworld_test
Started
F
Finished in 0.004184 seconds.
1) Failure:
test: HelloWorld should say "Hello, World!". (TestHelloWorld)
[examples/helloworld_test.rb:20:in `__bind_1220472042_539418'
/var/lib/gems/1.8/gems/Shoulda-1.2.0/lib/shoulda.rb:226:in `call'
/var/lib/gems/1.8/gems/Shoulda-1.2.0/lib/shoulda.rb:226:in `test: HelloWorld should say "Hello, World!". ']:
<"Hello, World!"> expected but was
<"Hello, World">.
1 tests, 1 assertions, 1 failures, 0 errors
With an equivalent RSpec specification the results look like this
HelloWorld
- should say "Hello, World!" (FAILED - 1)
1)
'HelloWorld should say "Hello, World!"' FAILED
expected: "Hello, World!",
got: "Hello, World" (using ==)
./examples/helloworld_spec.rb:17:
Finished in 0.006088 seconds
1 example, 1 failure
Implementation
Unlike RSpec which has its own runner logic, Shoulda is a simple add-on to Ruby’s standard Test::Unit suite. So, while MonkeySpecDoc is intended to be used with Shoulda, it also works with plain Test::Unit code. MonkeySpecDoc changes the output logic of the test runner code to separate the information about the test case or the Shoulda context from the name of the individual tests. It also does some tweaking with the output of status messages (OK, FAILED, and ERROR). Technically, what I did was monkey patching the console runner of Test::Unit (hence the name).
Currently, there are two ways to use MonkeySpecDoc:
- A run-script called mkspecdoc which takes the file to test on the command line, or
- by including specdoc.rb from the MonkeySpecDoc directory in a Rake-task that uses rake/runtest
Returning to the HelloWorld example, MonkeySpecDoc produces the following output:
Loaded suite /var/lib/gems/1.8/bin/rake
Started
HelloWorld:
- should say "Hello, World!": FAILED (1)
Finished in 0.004573 seconds.
1) HelloWorld should say "Hello, World!" FAILED:
[./helloworld_test.rb:20:in `__bind_1220473238_312818'
/var/lib/gems/1.8/gems/Shoulda-1.2.0/lib/shoulda.rb:226:in `call'
/var/lib/gems/1.8/gems/Shoulda-1.2.0/lib/shoulda.rb:226:in `test: HelloWorld should say "Hello, World!". ']:
<"Hello, World!"> expected but was
<"Hello, World">.
1 tests, 1 assertions, 1 failures, 0 errors
When we fix the error, MonkeySpecDoc says:
Loaded suite /var/lib/gems/1.8/bin/rake
Started
HelloWorld:
- should say "Hello, World!": OK
Finished in 0.000442 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
The code can be found on GitHub including the examples.
Update:
There is now also a Ruby Gem. Run the following if you haven’t added GitHub’s Gem repository to your sources already:
gem sources -a http://gems.github.com
Install the gem (Update Dec 18, 2008: project name now in lower case):
sudo gem install jgre-monkeyspecdoc
