如何编写只有在函数没有抛出预期异常时才会失败的单元测试呢?
当前回答
有4个选项(你会在最后找到完整的例子):
assertRaises与上下文管理器
def test_raises(self):
with self.assertRaises(RuntimeError):
raise RuntimeError()
如果你想检查异常消息(参见下面的"assertRaisesRegex with context manager"选项来检查它的一部分):
def test_raises(self):
with self.assertRaises(RuntimeError) as error:
raise RuntimeError("your exception message")
self.assertEqual(str(error.exception), "your exception message")
assertRaises一行程序
注意:这里使用的函数不是函数调用,而是可调用函数(不带圆括号)。
def test_raises(self):
self.assertRaises(RuntimeError, your_function)
assertRaisesRegex与上下文管理器
第二个参数是正则表达式,是必选项。当您只想检查部分异常消息时,非常方便。
def test_raises_regex(self):
with self.assertRaisesRegex(RuntimeError, r'.* exception message'):
raise RuntimeError('your exception message')
assertRaisesRegex一行程序
第二个参数是正则表达式,是必选项。当您只想检查部分异常消息时,非常方便。
注意:这里使用的函数不是函数调用,而是可调用函数(不带圆括号)。
def test_raises_regex(self):
self.assertRaisesRegex(RuntimeError, r'.* exception message', your_function)
完整的代码示例:
import unittest
def your_function():
raise RuntimeError('your exception message')
class YourTestCase(unittest.TestCase):
def test_1_raises_context_manager(self):
with self.assertRaises(RuntimeError):
your_function()
def test_1b_raises_context_manager_and_error_message(self):
with self.assertRaises(RuntimeError) as error:
your_function()
self.assertEqual(str(error.exception), "your exception message")
def test_2_raises_oneliner(self):
self.assertRaises(RuntimeError, your_function)
def test_3_raises_regex_context_manager(self):
with self.assertRaisesRegex(RuntimeError, r'.* exception message'):
your_function()
def test_4_raises_regex_oneliner(self):
self.assertRaisesRegex(RuntimeError, r'.* exception message', your_function)
if __name__ == '__main__':
unittest.main()
虽然这取决于开发人员遵循哪种风格,但我更喜欢使用上下文管理器的两种方法。
其他回答
对于Django上的那些,你可以使用上下文管理器来运行错误的函数,并使用assertRaisesMessage断言它会引发带有特定消息的异常
with self.assertRaisesMessage(SomeException,'Some error message e.g 404 Not Found'):
faulty_funtion()
我几乎在任何地方都使用doctest[1],因为我喜欢同时记录和测试我的函数。
看看这段代码:
def throw_up(something, gowrong=False):
"""
>>> throw_up('Fish n Chips')
Traceback (most recent call last):
...
Exception: Fish n Chips
>>> throw_up('Fish n Chips', gowrong=True)
'I feel fine!'
"""
if gowrong:
return "I feel fine!"
raise Exception(something)
if __name__ == '__main__':
import doctest
doctest.testmod()
如果您把这个例子放在一个模块中,并从命令行运行它,两个测试用例都会被评估和检查。
[1] Python文档:23.2 doctest——测试交互式Python示例
这里有很多答案。该代码展示了如何创建Exception,如何在方法中使用该异常,以及如何在单元测试中验证所引发的正确异常。
import unittest
class DeviceException(Exception):
def __init__(self, msg, code):
self.msg = msg
self.code = code
def __str__(self):
return repr("Error {}: {}".format(self.code, self.msg))
class MyDevice(object):
def __init__(self):
self.name = 'DefaultName'
def setParameter(self, param, value):
if isinstance(value, str):
setattr(self, param , value)
else:
raise DeviceException('Incorrect type of argument passed. Name expects a string', 100001)
def getParameter(self, param):
return getattr(self, param)
class TestMyDevice(unittest.TestCase):
def setUp(self):
self.dev1 = MyDevice()
def tearDown(self):
del self.dev1
def test_name(self):
""" Test for valid input for name parameter """
self.dev1.setParameter('name', 'MyDevice')
name = self.dev1.getParameter('name')
self.assertEqual(name, 'MyDevice')
def test_invalid_name(self):
""" Test to check if error is raised if invalid type of input is provided """
self.assertRaises(DeviceException, self.dev1.setParameter, 'name', 1234)
def test_exception_message(self):
""" Test to check if correct exception message and code is raised when incorrect value is passed """
with self.assertRaises(DeviceException) as cm:
self.dev1.setParameter('name', 1234)
self.assertEqual(cm.exception.msg, 'Incorrect type of argument passed. Name expects a string', 'mismatch in expected error message')
self.assertEqual(cm.exception.code, 100001, 'mismatch in expected error code')
if __name__ == '__main__':
unittest.main()
使用unittest进行单元测试将是首选,但如果您想快速修复,我们可以捕获异常,将其赋值给一个变量,并查看该变量是否是该异常类的实例。
假设我们的坏函数抛出一个ValueError。
try:
bad_function()
except ValueError as e:
assert isinstance(e, ValueError)
由于我还没有看到任何关于如何检查我们是否在使用上下文管理器的接受列表中获得特定异常的详细解释,或其他异常细节,我将添加我的(在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 manage.py命令?
- 我如何让红宝石打印一个完整的回溯而不是截断一个?
- Visual Studio:如何打破处理异常?
- 如何重置笑话模拟函数调用计数之前,每次测试
- 如何在Flask-SQLAlchemy中按id删除记录
- 在Python中插入列表的第一个位置
- Python Pandas只合并某些列
- 如何在一行中连接两个集而不使用“|”
- 从字符串中移除前缀
- 代码结束时发出警报
- 如何在Python中按字母顺序排序字符串中的字母
- 在matplotlib中将y轴标签添加到次要y轴
- 如何消除数独方块的凹凸缺陷?
- 为什么出现这个UnboundLocalError(闭包)?
- 使用Python请求的异步请求