我想编写一个测试,以确定在给定的情况下不会引发异常。

测试是否引发异常是很简单的…

sInvalidPath=AlwaysSuppliesAnInvalidPath()
self.assertRaises(PathIsNotAValidOne, MyObject, sInvalidPath) 

... 但你怎么能反其道而行之呢。

像这样的东西是我所追求的…

sValidPath=AlwaysSuppliesAValidPath()
self.assertNotRaises(PathIsNotAValidOne, MyObject, sValidPath) 

当前回答

def run_test(self):
    try:
        myFunc()
    except ExceptionType:
        self.fail("myFunc() raised ExceptionType unexpectedly!")

其他回答

嗨,我想写一个测试来确定在给定的情况下不会引发异常。

这是默认的假设——不引发异常。

如果你什么都没说,那在每个测试中都是假设的。

你不需要为它写任何断言。

def run_test(self):
    try:
        myFunc()
    except ExceptionType:
        self.fail("myFunc() raised ExceptionType unexpectedly!")

你可以试试。 试一试: 自我。assertRaises(没有,函数,__arg1、最长) 除了: 通过 如果你不把代码放在try块中,它会通过异常“AssertionError: None not raised”,测试用例将失败。如果将测试用例放入try块中,则测试用例将通过,这是预期的行为。

我发现monkey-patch unittest很有用,如下所示:

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))

你可以通过重用unittest模块中90%的assertRaises原始实现来定义assertNotRaises。使用这种方法,您最终得到一个assertNotRaises方法,除了它的反向失败条件外,它的行为与assertRaises完全相同。

TLDR和现场演示

在unittest中添加assertNotRaises方法非常简单。TestCase(写这个答案的时间是写代码的4倍)。下面是assertNotRaises方法的现场演示。就像assertRaises一样,你可以传递一个可调用对象和参数给assertNotRaises,或者你可以在with语句中使用它。现场演示包括一个测试用例,演示assertNotRaises按预期工作。

细节

在unittest中实现assertRaises是相当复杂的,但是通过一些聪明的子类化,你可以覆盖和逆转它的失败条件。

assertRaises是一个简短的方法,基本上只创建unittest.case的一个实例。_AssertRaisesContext类并返回它(参见unittest. context中的定义)。模块)。你可以通过继承_AssertRaisesContext的子类并覆盖它的__exit__方法来定义你自己的_AssertNotRaisesContext类:

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方法可用。