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.
精彩评论