Python如何在另一个函数中模拟一个函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python如何在另一个函数中模拟一个函数相关的知识,希望对你有一定的参考价值。

我对打破单元测试的功能进行了一些更改。以前我有一个包含函数request_url的common.py:

import requests

def request_url(method, url):
    return _request_url(method, url)

def _request_url(method, url):
    return requests.request(method, url)

这是测试:

@mock.patch("requests.request", autospec=True)
def test_request_url_200(self, mock_request):

    response = mock.MagicMock()
    response.status_code = 200
    method = mock.sentinel.method
    path = "url"

    result = common.request_url(
        method,
        path
    )

    self.assertListEqual([
        mock.call(
            mock.sentinel.method,
            "url"
        ),
    ], list(mock_request.mock_calls))

    self.assertListEqual([mock.call.raise_for_status()], list(response.mock_calls))
    self.assertEqual(mock_request.return_value, result)

在功能发生变化之后,我首先发起了一个会话,安装了一个TLS适配器,然后调用会话的请求函数,而不是简单地调用requests.request:

def _request_url(method, url):
    session = requests.session()
    adapter = TlsAdapter(ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1)
    session.mount("https://", adapter)
    return response = session.request(method, url)

在这里,我不确定如何完全模拟session.request,因为这可以通过session变量获得。我尝试修补requests.session.request,但这在这里不起作用。

有谁知道如何嘲笑这个功能?

谢谢!

答案

我认为在@mock.patch(...)的原因。你设置autospec=True,但你的mock_request不返回数据(在你的情况下每次 - Mock)。 The documentation说:

如果设置autospec = True,则将使用要替换的对象的规范创建模拟。 mock的所有属性也将具有要替换的对象的相应属性的规范。 ...

试着打电话:

print(mock_request.return_value) # <MagicMock name='request()()' id='4343989392'>
# or
# print(mock_request.return_value.return_value) # <MagicMock name='request()()()' id='4344191568'>

正如你所看到的,requests.request被'嘲笑',但没有返回任何数据。您可以使用return_valueside_effect设置预期数据。这是一个例子:

from unittest import TestCase
import mock
from common import request_url


class MyTestExample(TestCase):

    def test_request_url_1(self):
        mocked_request = mock.patch('requests.request', side_effect=['one', 'two', 'tree', ])
        mocked_request.start()
        # request_url(...) will return item from list
        self.assertEqual('one', request_url('test', 'url'))
        self.assertEqual('two', request_url('test', 'url'))
        self.assertEqual('tree', request_url('test', 'url'))

        mocked_request.stop()

    def test_request_url_2(self):
        result = {'my': 'dict'}
        mocked_request = mock.patch('requests.request', return_value=result)
        mocked_request.start()
        # request_url(...) will return static data 
        self.assertEqual(result, request_url('test', 'url'))
        self.assertEqual(result, request_url('test', 'url'))
        self.assertEqual(result, request_url('test', 'url'))

        mocked_request.stop()

因此,您只需要描述预期的数据。你也可以使用mock httpretty API。

希望这可以帮助。

以上是关于Python如何在另一个函数中模拟一个函数的主要内容,如果未能解决你的问题,请参考以下文章

模拟在另一个函数中使用的函数

使用 python 的模拟 patch.object 更改在另一个方法中调用的方法的返回值

Jest - 在另一个模块函数中模拟函数

python中是如何实现将一个函数中定义的变量在另一个函数中改变其值的

python在一个文件封装了几个函数,在另一个文件上导入这个文件来调用某一条函数,却直接运行了整个文件?

为啥在一个函数中声明的联合类型在另一个函数中使用无效?