单元测试中的自定义异常

Lud*_*udo 2 python unit-testing assertraises python-3.x python-unittest

我在其中创建了自定义异常 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

import unittest
with unittest.TestCase.assertRaises(DataException):
    foobar()
Run Code Online (Sandbox Code Playgroud)

正如这里建议的那样:Python assertRaises用户定义的异常

我收到此错误:

TypeError: assertRaises() missing 1 required positional argument: 'expected_exception'
Run Code Online (Sandbox Code Playgroud)

或者:

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

import unittest
unittest.TestCase.assertRaises(DataException, foobar)
Run Code Online (Sandbox Code Playgroud)

结果是:

TypeError: assertRaises() arg 1 must be an exception type or tuple of exception types
Run Code Online (Sandbox Code Playgroud)

为什么不承认DataException作为Exception?为什么链接的stackoverflow问题在没有提供第二个参数的情况下回答assertRaises

Mar*_*ers 6

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

unittest.TestCase.assertRaises是一种未绑定的方法.您可以在TestCase您定义的类的测试方法中使用它:

class DemoTestCase(unittest.TestCase):
    def test_foobar(self):
        with self.assertRaises(DataException):
            foobar()
Run Code Online (Sandbox Code Playgroud)

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

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

if __name__ == '__main__':
    unittest.main()
Run Code Online (Sandbox Code Playgroud)

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

在技​​术上可以在这样的环境之外使用断言,请参阅有没有办法在TestCase之外使用Python单元测试断言?,但我建议你坚持创建测试用例.

要进一步验证引发的异常上的代码和消息,请将输入上下文时返回的值分配给新名称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')
Run Code Online (Sandbox Code Playgroud)

请参阅TestCase.assertRaises()文档.

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