unittest: assertRaises() with an instance instead of a type

Ulrich Eckhardt ulrich.eckhardt at dominolaser.com
Wed Mar 28 14:28:08 CEST 2012


Hi!

I'm currently writing some tests for the error handling of some code. In 
this scenario, I must make sure that both the correct exception is 
raised and that the contained error code is correct:


   try:
       foo()
       self.fail('exception not raised')
   catch MyException as e:
       self.assertEqual(e.errorcode, SOME_FOO_ERROR)
   catch Exception:
       self.fail('unexpected exception raised')


This is tedious to write and read. The docs mention this alternative:


    with self.assertRaises(MyException) as cm:
        foo()
    self.assertEqual(cm.the_exception.errorcode, SOME_FOO_ERROR)


This is shorter, but I think there's an alternative syntax possible that 
would be even better:


     with self.assertRaises(MyException(SOME_FOO_ERROR)):
         foo()


Here, assertRaises() is not called with an exception type but with an 
exception instance. I'd implement it something like this:


     def assertRaises(self, exception, ...):
         # divide input parameter into type and instance
         if isinstance(exception, Exception):
             exception_type = type(exception)
         else:
             exception_type = exception
             exception = None
         # call testee and verify results
         try:
             ...call function here...
         except exception_type as e:
             if not exception is None:
                 self.assertEqual(e, exception)


This of course requires the exception to be equality-comparable.


Questions here:
1. Does this sound like a useful extension or am I missing another 
obvious solution to my problem?
2. The assertRaises() sketch above tries to auto-detect whether the 
given parameter is the type or an instance. Given the highly dynamic 
nature of Python, an object can be both instance and type, is the above 
detection mechanism reliable?


Of course I'm open for other suggestions to solve my problem. One that I 
thought of but which I haven't really looked into was to modify __init__ 
or __new__ of my exception class to return an instance of a derived 
class that uniquely identifies the error. I.e. 
MyException(SOME_FOO_ERROR) would not create a MyException instance but 
a MyFooErrorException instance (which has MyException as a baseclass). 
In that case, the existing code that checks for the right exception type 
would suffice for my needs.


Cheers everybody!

Uli



More information about the Python-list mailing list