单元测试中的自定义异常
Custom exceptions in unittests
我已经在 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
如果 pandas
数据帧中没有足够的数据,代码中其他地方的另一个函数会引发 DataException
的不同实例。我想使用 unittest
来确保它 returns 具有相应消息的适当异常。
使用一个简单的例子,为什么这不起作用:
from .. import DataException
def foobar():
raise DataException('E101')
import unittest
with unittest.TestCase.assertRaises(DataException):
foobar()
这里建议:
我收到这个错误:
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
为什么它不能将 DataException
识别为 Exception
?为什么链接的 Whosebug 问题答案在不向 assertRaises
提供第二个参数的情况下工作?
您试图在不创建实例的情况下使用 TestCase
class 的方法;这些方法并非旨在以这种方式使用。
unittest.TestCase.assertRaises
是一个 未绑定方法 。您可以在定义的 TestCase
class 的测试方法中使用它:
class DemoTestCase(unittest.TestCase):
def test_foobar(self):
with self.assertRaises(DataException):
foobar()
引发错误是因为未绑定方法未传入 self
。因为 unittest.TestCase.assertRaises
需要 self
和第二个名为 expected_exception
的参数,所以出现异常因为 DataException
作为 self
.
的值传入
您现在必须使用测试 运行ner 来管理您的测试用例;添加
if __name__ == '__main__':
unittest.main()
在底部和 运行 您的文件作为脚本。然后 auto-discovered 并执行您的测试用例。
在这种环境之外使用断言在技术上是可行的,请参阅 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()
documentation。
最后但同样重要的是,考虑使用 DataException
的 subclasses 而不是使用单独的错误代码。这样,您的 API 用户就可以捕获其中一个子 class 来处理特定的错误代码,而不必对代码进行额外的测试,并且 re-raise 如果特定的代码应该那里没有处理过。
我已经在 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
如果 pandas
数据帧中没有足够的数据,代码中其他地方的另一个函数会引发 DataException
的不同实例。我想使用 unittest
来确保它 returns 具有相应消息的适当异常。
使用一个简单的例子,为什么这不起作用:
from .. import DataException
def foobar():
raise DataException('E101')
import unittest
with unittest.TestCase.assertRaises(DataException):
foobar()
这里建议:
我收到这个错误:
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
为什么它不能将 DataException
识别为 Exception
?为什么链接的 Whosebug 问题答案在不向 assertRaises
提供第二个参数的情况下工作?
您试图在不创建实例的情况下使用 TestCase
class 的方法;这些方法并非旨在以这种方式使用。
unittest.TestCase.assertRaises
是一个 未绑定方法 。您可以在定义的 TestCase
class 的测试方法中使用它:
class DemoTestCase(unittest.TestCase):
def test_foobar(self):
with self.assertRaises(DataException):
foobar()
引发错误是因为未绑定方法未传入 self
。因为 unittest.TestCase.assertRaises
需要 self
和第二个名为 expected_exception
的参数,所以出现异常因为 DataException
作为 self
.
您现在必须使用测试 运行ner 来管理您的测试用例;添加
if __name__ == '__main__':
unittest.main()
在底部和 运行 您的文件作为脚本。然后 auto-discovered 并执行您的测试用例。
在这种环境之外使用断言在技术上是可行的,请参阅 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()
documentation。
最后但同样重要的是,考虑使用 DataException
的 subclasses 而不是使用单独的错误代码。这样,您的 API 用户就可以捕获其中一个子 class 来处理特定的错误代码,而不必对代码进行额外的测试,并且 re-raise 如果特定的代码应该那里没有处理过。