问题:Python单元测试-与assertRaises相反吗?
我想编写一个测试来确定在给定的情况下不引发异常。
测试是否引发异常很简单 …
sInvalidPath=AlwaysSuppliesAnInvalidPath()
self.assertRaises(PathIsNotAValidOne, MyObject, sInvalidPath)
…但是你怎么做相反。
像这样的东西我在追求…
sValidPath=AlwaysSuppliesAValidPath()
self.assertNotRaises(PathIsNotAValidOne, MyObject, sValidPath)
回答 0
def run_test(self):
try:
myFunc()
except ExceptionType:
self.fail("myFunc() raised ExceptionType unexpectedly!")
回答 1
嗨-我想编写一个测试来确定在给定的情况下不引发异常。
这是默认的假设-不引发异常。
如果您什么都没说,则在每个测试中都假设了这一点。
您不必为此写任何断言。
回答 2
只需调用该函数即可。如果引发异常,则单元测试框架会将其标记为错误。您可能要添加评论,例如:
sValidPath=AlwaysSuppliesAValidPath()
# Check PathIsNotAValidOne not thrown
MyObject(sValidPath)
回答 3
我是原始发布者,我没有在代码中首先使用它就接受了DGH的上述回答。
一旦我使用完,我意识到实际上需要做一些调整才能做我需要做的事情(为了公平对待DGH,他/她确实说了“或类似的话!”)。
我认为值得在这里发表一些调整以使他人受益:
try:
a = Application("abcdef", "")
except pySourceAidExceptions.PathIsNotAValidOne:
pass
except:
self.assertTrue(False)
我在这里尝试做的是确保如果尝试使用第二个空格参数实例化Application对象,则将引发pySourceAidExceptions.PathIsNotAValidOne。
我相信使用上面的代码(主要基于DGH的答案)可以做到。
回答 4
您可以定义assertNotRaises
通过重用对原执行的90%assertRaises
的中unittest
模块。使用这种方法,最终得到的assertNotRaises
方法除了其反向失败条件外,其行为与相同assertRaises
。
TLDR和现场演示
事实证明,向其中添加assertNotRaises
方法非常容易unittest.TestCase
(编写此答案所花的时间是代码的四倍,这使我花了大约四倍的时间)。这是该assertNotRaises
方法的现场演示。就像一样assertRaises
,您可以将callable和args传递给assertNotRaises
,也可以在with
语句中使用它。现场演示包括一个测试案例,演示了assertNotRaises
预期的工作方式。
细节
assertRaises
in 的实现unittest
相当复杂,但是通过一些巧妙的子类化,您可以覆盖和逆转其失败条件。
assertRaises
是一个简短的方法,基本上只创建unittest.case._AssertRaisesContext
类的实例并返回它(请参见unittest.case
模块中的定义)。您可以_AssertNotRaisesContext
通过继承_AssertRaisesContext
并覆盖其__exit__
方法来定义自己的类:
import traceback
from unittest.case import _AssertRaisesContext
class _AssertNotRaisesContext(_AssertRaisesContext):
def __exit__(self, exc_type, exc_value, tb):
if exc_type is not None:
self.exception = exc_value.with_traceback(None)
try:
exc_name = self.expected.__name__
except AttributeError:
exc_name = str(self.expected)
if self.obj_name:
self._raiseFailure("{} raised by {}".format(exc_name,
self.obj_name))
else:
self._raiseFailure("{} raised".format(exc_name))
else:
traceback.clear_frames(tb)
return True
通常,您可以通过从中继承来定义测试用例类TestCase
。如果您改为继承子类MyTestCase
:
class MyTestCase(unittest.TestCase):
def assertNotRaises(self, expected_exception, *args, **kwargs):
context = _AssertNotRaisesContext(expected_exception, self)
try:
return context.handle('assertNotRaises', args, kwargs)
finally:
context = None
现在,您所有的测试用例都将具有assertNotRaises
可用的方法。
回答 5
def _assertNotRaises(self, exception, obj, attr):
try:
result = getattr(obj, attr)
if hasattr(result, '__call__'):
result()
except Exception as e:
if isinstance(e, exception):
raise AssertionError('{}.{} raises {}.'.format(obj, attr, exception))
如果您需要接受参数,可以进行修改。
像
self._assertNotRaises(IndexError, array, 'sort')
回答 6
我发现unittest
按以下步骤进行Monkey补丁很有用:
def assertMayRaise(self, exception, expr):
if exception is None:
try:
expr()
except:
info = sys.exc_info()
self.fail('%s raised' % repr(info[0]))
else:
self.assertRaises(exception, expr)
unittest.TestCase.assertMayRaise = assertMayRaise
这在测试是否存在异常时阐明了意图:
self.assertMayRaise(None, does_not_raise)
这也简化了循环测试,我经常发现自己在做:
# ValueError is raised only for op(x,x), op(y,y) and op(z,z).
for i,(a,b) in enumerate(itertools.product([x,y,z], [x,y,z])):
self.assertMayRaise(None if i%4 else ValueError, lambda: op(a, b))
回答 7
如果将Exception类传递给assertRaises()
,则将提供一个上下文管理器。这可以提高测试的可读性:
# raise exception if Application created with bad data
with self.assertRaises(pySourceAidExceptions.PathIsNotAValidOne):
application = Application("abcdef", "")
这使您可以在代码中测试错误情况。
在这种情况下,您正在测试PathIsNotAValidOne
当您将无效参数传递给Application构造函数时引发的。
回答 8
你可以这样尝试。尝试:self.assertRaises(None,function,arg1,arg2)除外:如果不将代码放入try块,则通过,它将通过异常“ AssertionError:未引发”,测试用例将失败。测试用例将通过如果放在try块中,这是预期的行为。
回答 9
确保对象初始化没有任何错误的一种简单方法是测试对象的类型实例。
这是一个例子:
p = SomeClass(param1=_param1_value)
self.assertTrue(isinstance(p, SomeClass))