开发者

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,开发者_C百科 self.raiser.raiseMyError)


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


As mentioned, the issue is modules __main__ and derived are not one and the same; this answer is about how you fix that.

Don't mix module code and script code. Start to think of if __name__ == "__main__" code as a hack. (It's still very convenient at times and I use it often for debugging, etc., but view it as a hack so you always get a slight mental nudge writing it.) The new script that would then run everything would be simple (and never imported):

#!/usr/bin/env python
import derived
import sys
sys.exit(derived.main(sys.argv[1:]))

Or with various differences by personal preference. Just make sure you add derived.main to do what you want.

I've also seen another hack which is less common, at the top of derived.py:

import sys
if __name__ == "__main__":
  import derived # import the same module under its "correct" name
  sys.exit(derived.main(sys.argv[1:]))

While wasteful in parsing the same code twice, this is self-contained in exchange.


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.


The problem is probably that your BaseClass.get() method is returning you another class. By the way, that method is horrible in itself, I wonder why you're doing this.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜