#coding   #fun   #ruby   #whatever

assert_raises_kind_of with Module error tagging

June 24, 2007

this sunny sunday afternoon i was putting together some utility code(stupid me!) to do some remote blogging from the shell or the cosy inside of my vim editing session. This for some later time, but while i was going on with my test-driven/test first development i hit the problem of missing a test to check for the base class of my errors. I wanted to:

assert_raise(StandardError) { @blog.find_post(:postid => 123456789) }

to generally check for any kind of trouble bubbling up but it was not working as expected. Instead i got nasty Failure reports:

1) Failure:
test_find_post(XMLRPCTest) [mylib.rb:83]:
<StandardError> exception expected but was
Class: <XMLRPC::FaultException>
Message: <"Sorry, no such post.">

I suspected XMLRPCTest::FaultException to maybe not beeing derived from StandardError, but that was not the case. A look in the ruby documentation and the ruby-talk thread confirmed:

assert_raise(*args) {|| ...} is checking for the EXCACT exception type only!

How was it for you?

On the ruby-talk mailing list there was a little discussion about this topic and i pretty much agree with all the +1 sayers on the list. Edwin Fine propsed adding his own assert_raise_s method the Assertions class. You easily get into muddy waters with opening standard ruby classes for some duck-typing but reverting to:

assert_raise(XMLRPC::FaultException) { @blog.find_post(:postid => 123456789) }

was not an option. This would expose way to much implementation detail to this very high level coding of the very first tests so early in the project. So I was using the source, as yoda said and found another solution for me.

Modules as base class arguments to assert_raises

After i read Edwin’s post i checked the source for def
assert_raise
and learned that this method is actually checking for some kind of exception base class. The argument to assert_raise is an array of exception types. assert_raise does partition this types into Class and Module.

The assertion_raise checks for Class types is exact, but the Module is not(can’t be). They are checked with an is_a? condition - there can’t be no object instance of module type or course.

My original test therefor simply fails because StandardError is not a Module but a class. The XMLRPC::FaultException implementation is not mine but it is bubbling through my lib which i’m testing and this is precisly the condition i want to write tests for.

“Module tagged” exceptions and assert_raises_kind_of

First i wrote an empty tagging module for lib to tag all Errors and exceptions coming from my lib:

module MyLib
    module Error; end
end

Now i can tag all exception from some deeper laying code with my Error module:

begin
    ...
rescue => e # errors bubbling from the underworld
        # tag it
    class << e; include MyLib::Error; end 
        # throw it
    raise e
end

Voila, and now i can write:

assert_raise(BlogMist::Error) { @blog.find_post(:postid => 123456789) }

and finally got what i wanted but you’re milage may vary. Basically this gives me a way to create some kind of folksonomy of errors coming from my library. Don’t know yet where this might lead me, but hey, ruby is the best for protoyping and playing around!

Don’t be lazy!

Testing for error base classes instead of pricise error handling is not to make you lazy! As discussed on the forum thread it is to start with tests early on and being able to refine error condition testing over time.

Technorati tag: , , , ,

share this: