【问题标题】:Integration test for decorated function装饰功能的集成测试
【发布时间】: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


【解决方案1】:

上面测试的工作版本如下:

import unittest
from unittest.mock import patch

import myproj


class MyTestCase(unittest.TestCase):
    @patch("myproj.problematic_func")
    def test_no_exception_raises(self, mock_problematic_func):
        mock_problematic_func.side_effect = Exception("Boom")
        myproj.problematic_func = myproj.catch_every_error(mock_problematic_func)

        try:
            myproj.func_under_test()
        except Exception:
            self.fail(
                "exception in problematic function propagated to 'func_under_test'"
            )


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

之前我试过(没有成功):

from myproj import catch_every_error

mock_problematic_func = catch_every_error(mock_problematic_func)

由于某种原因(我不太清楚),使用from 语句导入函数并手动装饰不起作用。尽管导入整个模块 (import myproj) 并使用重置属性 (myproj.problematic_func =) 进行手动装饰是有效的。

【讨论】:

    猜你喜欢
    • 2011-04-09
    • 2014-04-24
    • 1970-01-01
    • 2013-08-06
    • 2022-01-09
    • 1970-01-01
    • 2020-09-25
    • 2016-08-27
    • 1970-01-01
    相关资源
    最近更新 更多