Python unittest - 与assertRaises相反?

时间:2010-11-30 23:34:52

标签: python unit-testing

我想写一个测试来确定在给定的环境中不会引发异常。

可以直接测试异常 是否会被提升......

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

...但你怎么能做反面

像我这样的东西我正在追求......

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

9 个答案:

答案 0 :(得分:319)

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

答案 1 :(得分:57)

  

嗨 - 我想编写一个测试来确定在特定情况下不会引发异常。

这是默认假设 - 不会引发异常。

如果你不说别的话,那就是在每次测试中都假设的。

您不必为此实际编写任何断言。

答案 2 :(得分:50)

只需调用该函数即可。如果它引发异常,单元测试框架会将此标记为错误。您可能想添加评论,例如:

sValidPath=AlwaysSuppliesAValidPath()
# Check PathIsNotAValidOne not thrown
MyObject(sValidPath)

答案 3 :(得分:13)

我是原始海报,我在没有首先在代码中使用它的情况下接受了DGH的上述答案。

一旦我使用了,我意识到需要做一些调整才能真正做我需要做的事情(对DGH来说,他/她确实说“或类似的东西”!)。

我认为为了别人的利益而在这里发布调整是值得的:

    try:
        a = Application("abcdef", "")
    except pySourceAidExceptions.PathIsNotAValidOne:
        pass
    except:
        self.assertTrue(False)

我在这里尝试做的是确保如果尝试使用第二个空格参数实例化Application对象,则会引发pySourceAidExceptions.PathIsNotAValidOne。

我相信使用上面的代码(主要基于DGH的答案)会做到这一点。

答案 4 :(得分:5)

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

TLDR和现场演示

事实证明,将assertNotRaises方法添加到unittest.TestCase非常容易(编写此答案的时间大约是代码的4倍)。这是a live demo of the assertNotRaises method in action。只需like assertRaises,您就可以将callable和args传递给assertNotRaises,也可以在with语句中使用它。实时演示包含一个测试用例,用于演示assertNotRaises是否按预期工作。

详细信息

assertRaisesunittest的实现相当复杂,但通过一些聪明的子类,您可以覆盖并反转其失败条件。

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 :(得分:1)

如果将Exception类传递给assertRaises(),则会提供上下文管理器。这可以提高测试的可读性:

# raise exception if Application created with bad data
with self.assertRaises(pySourceAidExceptions.PathIsNotAValidOne):
    application = Application("abcdef", "")

这允许您在代码中测试错误情况。

在这种情况下,您正在测试将无效参数传递给Application构造函数时引发的PathIsNotAValidOne

答案 6 :(得分:1)

我发现对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))

答案 7 :(得分:0)

您可以尝试这样。         尝试:             self.assertRaises(None,function,arg1,arg2)         除了:             通过 如果您不将代码放入try块中,它将通过异常“ AssertionError:None not not凸起”,并且测试用例将失败。如果将其放入预期的行为中,则将通过测试用例。

答案 8 :(得分:0)

确保对象初始化没有任何错误的一种简单方法是测试对象的类型实例。

这里是一个例子:

p = SomeClass(param1=_param1_value)
self.assertTrue(isinstance(p, SomeClass))