Ruby TestCase: Resumable Assertions

14 02 2008

It’s hard to believe that, for all of Smalltalk’s elegance, it isn’t more widely accepted. I just read the SUnit chapter in Squeak By Example. The SUnit TestCase class has a resumable assert method (TestCase#assert:description:resumable:). The use case for this is testing objects in a collection. Here’s a code example:

(1 to: 30) do: [ :each |
    self assert: each even description: each printString, ' is odd' resumable: true]

This code produces a test failure and outputs each object in the collection that fails the test (every odd number, in this example).

I decided that I wanted something like that in Ruby. Well, I want it in Java too, but coding in Java’s no fun 🙂

I was thinking of something like this:

1.upto 30 do | each |
       assert_and_resume each % 2 == 0, "#{each} is odd"

After poking through the TestCase source, I decided the easiest approach would be to write a custom assert, wrapping the assert_block method. I just needed to be able to catch the failed assertion and report the failure without stopping the test method.

So I wrangled a little code and came up with a solution that works like this:

1.upto 30 do | each |
       assert_and_resume( "#{ each } is odd" ) { each % 2 == 0 }

Pretty close to what I was thinking.

And here’s the implementation:

module Test
  module Unit

    # Resumable assertions are in a different module then the other
    # assertions because they have a dependency on
    # TestCase#add_failure.  The standard assertions can be included
    # anywhere, so including Resumable assertions in the Assertions
    # module might break existing code.
    module ResumableAssertions

      require 'test/unit/assertions'
      def assert_and_resume( description, &block )
          assert_block description, &block
        rescue AssertionFailedError => e
          add_failure e.message, e.backtrace


    # Now we hook our assertion up to the test case. I could have just
    # re-opened TestCase, but I wanted to keep the Assertion logic
    # separate from the TestCase logic, as was the original author's
    # design.
    require 'test/unit/testcase'
    TestCase.send( :include, ResumableAssertions )


Not much to it. The only other change that I might like to make is to modify the output so that it’s clear that one method failed many times. On a lark, I ran this through ci_reporter and then used Antwrap to generate a junit report. Here’s an snapshot of what that report looks like:

Resumable Assert Test Report




2 responses

20 05 2011

Interesting. Maybe all assertions should resume?

20 05 2011

Ah, sorry, I forgot to click on “Notify me of follow-up comments via email.”

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: