如何在python中模拟导入的pypi库使用的函数调用 [英] how to mock function call used by imported pypi library in python

查看:55
本文介绍了如何在python中模拟导入的pypi库使用的函数调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码要测试:

great_report.py

great_report.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

我有我的测试函数,该函数模拟_get_report_link_from_3rd_party来测试所有内容,但我不希望该函数在运行测试时实际暂停执行.

I've got my testing function which mocks _get_report_link_from_3rd_party which tests everything but I don't want this function to actually pause execution during when I run tests..

@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)

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

I tried mocking the retry parameters but am running into issues where get_link keeps retrying over and over which causes long build times instead of just raising the exception and continuing. How can I mock the parameters for the @retry call in my test?

推荐答案

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

There is no way to change decorators parameters after load the module. Decorators decorate the original function and change it at the module load time.

首先,我想鼓励您对设计进行一些更改,使其更具可测试性.

First I would like encourage you to change your design a little to make it more testable.

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

If you extract the body of get_link() method test the new method and trust retry decorator you will obtain your goal.

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

If you don't want add a new method to your class you can use a config module that store variables that you use when call retry decorator. After that you can use two different module for testing and production.

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

The last way is the hacking way where you replace retry.api.__retry_internal by a your version that invoke the original one by changing just the variables:

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)

恕我直言,仅当您背靠墙且没有机会重新设计代码以使其更具可测试性时,才应使用该黑客解决方案. 内部函数/类/方法可能会更改,恕不另行通知,并且将来可能难以维护您的测试.

IMHO you should use that hacking solution only if you are with the back on the wall and you have no chance to redesign you code to make it more testable. The internal function/class/method can change without notice and your test can be difficult to maintain in the future.

这篇关于如何在python中模拟导入的pypi库使用的函数调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆