pythonunit-testingassertraises

assertRaises just catches base exception


I'm running into a strange problem when using unittest.assertRaises. When executing the code below I get the following output:

E
======================================================================
ERROR: testAssertRaises (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\home\python_test\src\derived.py", line 29, in testAssertRaises
    self.assertRaises(MyError, self.raiser.raiseMyError)
  File "C:\Programme\Python26\lib\unittest.py", line 336, in failUnlessRaises
    callableObj(*args, **kwargs)
  File "C:\home\python_test\src\derived.py", line 15, in raiseMyError
    raise MyError("My message")
MyError: 'My message'

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

The correct exception gets raised, but the test fails! If I'm catching the BaseError the test succeeds.

Somehow this seems to be a scope issue of unittest not being able to see the MyError exception class. Can someone explain that? Is there some workaround?

I am testing the following Python code which is an implementation for dynamically constructing objects by their class names.

This is the base module "bases.py":

class BaseClass(object):

    @staticmethod
    def get(className):
        module = __import__("derived", globals(), locals(), [className])
        theClass = getattr(module, className)
        return theClass()


class BaseError(Exception):

    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return repr(self.msg)

This is the module to test, "derived.py":

import unittest

from bases import BaseError
from bases import BaseClass


class MyErrorRaiser(BaseClass):    

    def raiseMyError(self):
        raise MyError("My message")


class MyError(BaseError):
    '''
    '''


class Test(unittest.TestCase):

    def setUp(self):
        self.raiser = BaseClass.get("MyErrorRaiser")

    def testAssertRaises(self):
        self.assertRaises(MyError, self.raiser.raiseMyError)


if __name__ == "__main__":
    unittest.main()

Solution

  • When you run derived.py, it is run as the __main__ module (since you ran it directly rather than importing it). When you later import it explicitly, another copy of the module is created, this time under the name derived. So __main__.MyError is not the same as derived.MyError, and the exception isn't caught.