Test Rig
Test Rig provides two separate modules that work together. Dynamic assertions are flexible xUnit style matchers called dynamically. Smarter message supplements test failure messages with a several-line context of the test failure. This library works well with something like Context or Shoulda.
Installation
If necessary, install Gemcutter.
sudo gem install gemcutter && sudo gem tumble
Install test-rig
sudo gem install test-rig
Add require 'test_rig'
to test_helper.rb, and include TestRig
into Test::Unit:TestCase
.
If you only want dynamic assertions or smarter messages, include TestRig::DynamicAssertions
or include TestRig::SmarterMessage
instead of TestRig
.
Dynamic assertions
Background & Philosophy
Rspec has never sat well for me. Object.method.should be_true style testing reads neat and is really nicely like english. Here’s the problem: What we are strictly saying in rspec is that testing is the object’s responsibility. It’s like “hey, you! test yourself.”
Testing is definitionally an external act. It is manipulating a system by its control points (public api) and confirming that the behavior is as expected. Passing a modal verb like “should” to the object in question does not describe this behavior.
From a more practical perspective, defining rspec behaviors is way too much of a pain when we already have an easy way to define methods in ruby.
Test::Unit
, particularly when combined with Context or Shoulda, is good
enough for most things. The only real issue is that you find yourself defining
a whole lot of helper methods, like assert_new_record
, assert_valid
, assert_red
Dynamic assertions fixes this. With the fantastic power of method missing,
assertions are generated on the fly.
One of the really nice things about Rspec is that every matcher automatically gets an inverse (logical not) matcher. Dynamic assertions provides this as well.
Example
Let’s say we have class named Entry
that has a boolean published?
and a
boolean saved?
and a record @foo
that should be saved but not published.
Oh, and it should have a user, which we’ll represent as the string "joe"
Positive assertions
In Rspec: @foo.should be_saved
In Test::Unit: assert @foo.saved?
With Dynamic assertions: assert_saved @foo
Negative assertions
In Rspec: @foo.should_not be_published
In Test::Unit: assert [email protected]?
or, if you’ve defined assert_false
, assert_false @foo.published
With Dynamic assertions: assert_not_published @foo
Positive equality assertions
In Rspec: @foo.user.should == "joe"
In Test::Unit: assert_equal "joe", @foo.user
With Dynamic assertions: assert_user "joe", @foo
Negative equality assertions
In Rspec: @foo.user.should == "joe"
In Test::Unit: assert_not_equal "joe", @foo.user
With Dynamic assertions: assert_not_user "joe", @foo
Everything else
assert @foo.user.include?('j')
assert_not @foo.user.include?('z')
Smarter Message
My bane: “false did not equal true” — What you really want to know is what the variable names were or the method calls.
If we have the stack trace, we should be able to show you the exact test that failed immediately. Smarter Message does exactly that.
Example
#demo_test.rb
require File.join(File.dirname(__FILE__), "test_helper")
require 'smarter_message'
class DemoTest < Test::Unit::TestCase
include TestRig::SmarterMessage
test "demonstration" do
a = 'foo'
b = 'bar'
assert_equal a, b
end
end
1) Failure:
test demonstration(DemoTest) [./test/demo_test.rb:11]:
<"foo"> expected but was
<"bar">.
./test/smarter_message_test.rb:11:in `test demonstration'
9: a = 'foo'
10: b = 'bar'
--> 11: assert_equal a, b
12: end
13:end
Settings
TestRig::SmarterMessage.context_lines = 2 #the default
This defaults to two (yielding five lines; two context on each side + the actual line). Set this in your test_helper. If context_lines is zero, it will just print your failure line.