assertRaises仅捕获基本异常
我在使用 unittest.assertRaises
的时候遇到了一个奇怪的问题。当我执行下面的代码时,得到了以下输出:
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)
虽然正确的异常被抛出了,但测试却失败了!如果我捕获 BaseError
,测试就成功了。
看起来这似乎是一个作用域的问题,unittest 似乎无法识别 MyError
这个异常类。有人能解释一下吗?有没有什么解决办法?
我正在测试以下 Python 代码,这段代码是用来根据类名动态构建对象的。
这是基础模块 "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)
这是要测试的模块 "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()
3 个回答
这个问题可能是因为你的 BaseClass.get()
方法返回了另一个类。顺便说一下,这个方法本身就很糟糕,我很好奇你为什么要这样做。
正如提到的,问题在于模块__main__和derived并不是同一个东西;这段内容是关于如何解决这个问题的。
不要把模块代码和脚本代码混在一起。开始把if __name__ == "__main__"
这段代码当作一种小技巧来看待。(虽然在某些时候它非常方便,我也经常用它来调试等等,但把它当作小技巧可以让你在写的时候有一点心理上的提醒。)接下来要运行的脚本会很简单(并且永远不会被导入):
#!/usr/bin/env python
import derived
import sys
sys.exit(derived.main(sys.argv[1:]))
或者根据个人喜好有各种不同的写法。只要确保你添加了derived.main来实现你想要的功能。
我还见过另一种不太常见的小技巧,放在derived.py的顶部:
import sys
if __name__ == "__main__":
import derived # import the same module under its "correct" name
sys.exit(derived.main(sys.argv[1:]))
虽然这样做会浪费时间重复解析同一段代码,但这样做是自给自足的。
当你直接运行 derived.py 这个文件时,它会作为 __main__
模块被执行(因为你是直接运行它,而不是通过其他地方引入)。但是,当你之后明确地导入这个模块时,系统会创建这个模块的另一个副本,这次它的名字是 derived
。所以 __main__.MyError
和 derived.MyError
其实是两个不同的东西,因此这个错误没有被捕捉到。