如何模拟python中导入的pypi库使用的函数调用

Ken*_*tor 1 python unit-testing mocking

我有以下代码要测试:

伟大的报告.py

from retry import retry

@retry((ReportNotReadyException), tries=3, delay=10, backoff=3)
def get_link(self):
    report_link = _get_report_link_from_3rd_party(params)
    if report_link:
        return report_link
    else:
        stats.count("report_not_ready", 1)
        raise ReportNotReadyException
Run Code Online (Sandbox Code Playgroud)

我有我的测试功能,它模拟 _get_report_link_from_3rd_party 测试所有内容,但我不希望此功能在我运行测试期间实际暂停执行..

@mock.patch('repo.great_report._get_report_link_from_3rd_party', return_value=None)
test_get_link_raises_exception(self, mock_get_report_link):
    self.assertRaises(ReportNotReadyException, get_link)
Run Code Online (Sandbox Code Playgroud)

我尝试模拟重试参数,但遇到了 get_link 不断重试的问题,这会导致构建时间过长,而不仅仅是引发异常并继续。如何在我的测试中模拟 @retry 调用的参数?

Tza*_*ach 8

正如此处所暗示的,防止实际睡眠的一种简单方法是修补该time.sleep函数。这是为我做的代码:

@patch('time.sleep', side_effect = lambda _: None)
Run Code Online (Sandbox Code Playgroud)


Mic*_*ico 5

加载模块后无法更改装饰器参数。装饰器装饰原始函数并在模块加载时对其进行更改。

首先,我想鼓励你稍微改变你的设计,使其更易于测试。

如果您提取get_link()方法体测试新方法并信任retry装饰器,您将获得目标。

如果您不想向类添加新方法,则可以使用配置模块来存储调用retry装饰器时使用的变量。之后,您可以使用两个不同的模块进行测试和生产。

最后一种方法是 hacking 方法,您可以retry.api.__retry_internal通过仅更改变量来调用原始版本来替换您的版本:

import unittest
from unittest.mock import *
from pd import get_link, ReportNotReadyException

import retry
orig_retry_internal = retry.api.__retry_internal
def _force_retry_params(new_tries=-1, new_delay=0, new_max_delay=None, new_backoff=1, new_jitter=0):
    def my_retry_internals(f, exceptions, tries, delay, max_delay, backoff, jitter, logger):
        # call original __retry_internal by new parameters
        return orig_retry_internal(f, exceptions, tries=new_tries, delay=new_delay, max_delay=new_max_delay,
                                   backoff=new_backoff, jitter=new_jitter, logger=logger)
    return my_retry_internals


class MyTestCase(unittest.TestCase):
    @patch("retry.api.__retry_internal", side_effect=_force_retry_params(new_tries=1))
    def test_something(self, m_retry):
        self.assertRaises(ReportNotReadyException, get_link, None)
Run Code Online (Sandbox Code Playgroud)

恕我直言,只有当您背井离乡并且您没有机会重新设计代码以使其更具可测试性时,您才应该使用该黑客解决方案。内部函数/类/方法可以在没有通知的情况下更改,并且您的测试将来可能难以维护