如何在python中模拟导入的pypi库使用的函数调用 [英] how to mock function call used by imported pypi library in python
问题描述
我有以下代码要测试:
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屋!