如何编写只有在函数没有抛出预期异常时才会失败的单元测试呢?


当前回答

由于我还没有看到任何关于如何检查我们是否在使用上下文管理器的接受列表中获得特定异常的详细解释,或其他异常细节,我将添加我的(在Python 3.8上检查)。

如果我只是想检查函数是否引发实例TypeError,我会写:

with self.assertRaises(TypeError):
    function_raising_some_exception(parameters)

如果我想检查函数是否引发TypeError或IndexError,我会写:

with self.assertRaises((TypeError,IndexError)):
    function_raising_some_exception(parameters)

如果我想要更多关于异常引发的细节,我可以在这样的上下文中捕获它:

# Here I catch any exception
with self.assertRaises(Exception) as e:
    function_raising_some_exception(parameters)

# Here I check actual exception type (but I could
# check anything else about that specific exception,
# like it's actual message or values stored in the exception)
self.assertTrue(type(e.exception) in [TypeError,MatrixIsSingular])

其他回答

对于Django上的那些,你可以使用上下文管理器来运行错误的函数,并使用assertRaisesMessage断言它会引发带有特定消息的异常

with self.assertRaisesMessage(SomeException,'Some error message e.g 404 Not Found'):
    faulty_funtion()

你的代码应该遵循这个模式(这是一个unittest模块风格测试):

def test_afunction_throws_exception(self):
    try:
        afunction()
    except ExpectedException:
        pass
    except Exception:
       self.fail('unexpected exception raised')
    else:
       self.fail('ExpectedException not raised')

在Python < 2.7中,此构造用于检查预期异常中的特定值。unittest函数assertRaises只检查是否引发了异常。

你可以使用unittest模块中的assertRaises:

import unittest

class TestClass():
  def raises_exception(self):
    raise Exception("test")

class MyTestCase(unittest.TestCase):
  def test_if_method_raises_correct_exception(self):
    test_class = TestClass()
    # Note that you don’t use () when passing the method to assertRaises
    self.assertRaises(Exception, test_class.raises_exception)

使用unittest进行单元测试将是首选,但如果您想快速修复,我们可以捕获异常,将其赋值给一个变量,并查看该变量是否是该异常类的实例。

假设我们的坏函数抛出一个ValueError。

    try:
      bad_function()
    except ValueError as e:
      assert isinstance(e, ValueError)

如果你正在使用pytest,你可以使用pytest.raise (Exception):

例子:

def test_div_zero():
    with pytest.raises(ZeroDivisionError):
        1/0

结果是:

$ py.test
================= test session starts =================
platform linux2 -- Python 2.6.6 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collected 1 items

tests/test_div_zero.py:6: test_div_zero PASSED

或者你可以构建自己的上下文管理器来检查异常是否被引发。

import contextlib

@contextlib.contextmanager
def raises(exception):
    try:
        yield
    except exception as e:
        assert True
    else:
        assert False

然后你可以像这样使用加薪:

with raises(Exception):
    print "Hola"  # Calls assert False

with raises(Exception):
    raise Exception  # Calls assert True