【发布时间】:2021-04-06 03:52:05
【问题描述】:
我在为调用其他已修饰函数的函数编写集成测试时遇到问题。假设有以下定义:
# myproj.py
import logging
def catch_every_error(func):
logger = logging.getLogger("mylogger")
def wrapper(*args, **kwargs):
try:
result = func(*args, **kwargs)
except Exception as e:
logger.exception("")
else:
return result
return wrapper
@catch_every_error
def problematic_func():
pass
def func_under_test():
# doing something very critical here
# ....
problematic_func()
我需要编写测试以确保problematic_func 内部引发的任何异常都不会传播到func_under_test。出于这个原因,我使用了如下模拟:
import unittest
from unittest.mock import patch
from myproj import func_under_test
class MyTestCase(unittest.TestCase):
@patch("myproj.problematic_func")
def test_no_exception_raises(self, mock_problematic_func):
mock_problematic_func.side_effect = Exception("Boom")
try:
func_under_test()
except Exception:
self.fail(
"exception in problematic function propagated to 'func_under_test'"
)
if __name__ == "__main__":
unittest.main()
问题是我不能通过这个测试。修补 problematic_func 导致删除了应用于该函数的装饰器,并且未捕获异常。对于手动应用装饰器,我尝试了:
mock_problematic_func = catch_every_error(mock_problematic_func)
这也不会导致成功的测试通过。在我的测试用例中调用 func_under_test 时仍然会引发异常。我应该如何测试problematic_func 内部引发的任何异常不会导致func_under_test 失败?
注意:请不要建议为 catch_every_error 装饰器编写测试。我正在尝试完成 func_under_test 的集成测试。
【问题讨论】:
-
catch_every_error替换原来的函数用一个被包装的函数分配给相同的名字。您的模拟对象没有被装饰器包裹;它完全取代了它。 -
@chepner 我知道。但是为什么
mock_problematic_func = catch_every_error(mock_problematic_func)不起作用? -
因为现在
mock_problematic_func不是mock对象;它是一个封装了一个mock对象的函数,所以它的side_effect属性没有特殊意义。 -
@chepner 在这种情况下您将如何实现所需的测试?
标签: python unit-testing mocking integration-testing python-decorators