10

我已经在其中创建了我的自定义异常errors.py

mapper = {
    'E101':
    'There is no data at all for these constraints',
    'E102':
    'There is no data for these constraints in this market, try changing market',
    'E103':
    'There is no data for these constraints during these dates, try changing dates',
}


class DataException(Exception):
    def __init__(self, code):
        super().__init__()
        self.msg = mapper[code]

    def __str__(self):
        return self.msg

代码中其他地方的另一个函数会引发不同的实例,说明数据帧DataException中是否没有足够的pandas数据。我想用unittest它来确保它返回适当的异常及其相应的消息。

使用一个简单的例子,为什么这不起作用:

from .. import DataException
def foobar():
    raise DataException('E101')

import unittest
with unittest.TestCase.assertRaises(DataException):
    foobar()

如此处所建议:Python assertRaises on user-defined exceptions

我收到此错误:

TypeError: assertRaises() missing 1 required positional argument: 'expected_exception'

或者:

def foobar():
    raise DataException('E101')

import unittest
unittest.TestCase.assertRaises(DataException, foobar)

结果是:

TypeError: assertRaises() arg 1 must be an exception type or tuple of exception types

为什么它不被识别DataExceptionException?为什么链接的stackoverflow问题答案在不提供第二个参数的情况下工作assertRaises

4

1 回答 1

13

您正在尝试使用TestCase类的方法而不创建实例;这些方法并非旨在以这种方式使用。

unittest.TestCase.assertRaises是一个未绑定的方法。您将在TestCase您定义的类的测试方法中使用它:

class DemoTestCase(unittest.TestCase):
    def test_foobar(self):
        with self.assertRaises(DataException):
            foobar()

引发错误是因为未self传递未绑定的方法。因为unittest.TestCase.assertRaises期望这两个self参数和名为的第二个参数expected_exception,您会得到一个异常,因为DataException它作为 的值传入self

您现在必须使用测试运行器来管理您的测试用例;添加

if __name__ == '__main__':
    unittest.main()

在底部并将您的文件作为脚本运行。然后自动发现并执行您的测试用例。

在这种环境之外使用断言在技术上是可行的,请参阅Is there a way to use Python unit test assertions outside of a TestCase? ,但我建议您坚持创建测试用例。

要进一步验证引发异常的代码和消息,请将输入上下文时返回的值分配给一个新名称,使用with ... as <target>:; 上下文管理器对象捕获引发的异常,因此您可以对其进行断言:

with self.assertRaises(DataException) as context:
    foobar()

self.assertEqual(context.exception.code, 'E101')
self.assertEqual(
    context.exception.msg,
    'There is no data at all for these constraints')

请参阅TestCase.assertRaises()文档

最后但同样重要的是,考虑使用的子类DataException不是使用单独的错误代码。这样,您的 API 用户可以只捕获其中一个子类来处理特定的错误代码,而不必对代码进行额外的测试并在不应该在那里处理特定代码时重新引发。

于 2018-03-19T17:40:28.687 回答