猿问

修补函数的 assert_call_with

我试图断言包装在另一个函数中的修补 request.get() 调用的输入。


def get_data(*args):

    # logic to define url, based on '*args'

    url = 'some_url?arg1&arg3'


    # call I want to patch and assert the url of

    response = request.get(url)


    # process response

    stuff = 'processed_response'

    return stuff

测试脚本:


def mock_response_200(url):

    response = mock.MagicMock()

    response.status_code = 200

    response.json = mock.Mock(return_value={  

        0: {'key1': 'value1', 'key2': 'value2'}

    })

    return response


@mock.patch('request.get', new=mock_response_200)

def test_get_data():

    arg1 = 'arg1'

    arg2 = None

    arg3 = 'arg3'


    stuff = get_data(arg1, arg2, arg3)

    # <assert input arguments of patched function here>

如何断言传递给 mocked_response_200 的 url?mocked_response_200 在 test_get_data 中不是“已知的”。

我已经在这里查看了其他帖子这一篇很接近,但答案使用了不同的补丁方法。任何帮助将不胜感激。


尚方宝剑之说
浏览 154回答 3
3回答

拉莫斯之舞

您正在修补模块中的未知get对象request。您可能没有这样的模块或对象。您需要在request被测模块中寻址对象。如果get_data位于模块中views,那么您需要在views.request.get此处打补丁:@mock.patch('views.request.get', new=mock_response_200)从mock.patch()文档:目标应该是形式为 的字符串'package.module.ClassName'。目标被导入并且指定的对象替换为新对象,因此目标必须可从您正在调用的环境中导入patch()。目标是在执行装饰函数时导入的,而不是在装饰时导入。我不是在这里使用的功能都不过。只需让模拟get()为您修补方法,然后配置该模拟对象。您当然可以将其委托给辅助函数:def config_response_200_mock(request_get):&nbsp; &nbsp; response = request_get.return_value&nbsp; &nbsp; response.status_code = 200&nbsp; &nbsp; response.json.return_value = {&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; 0: {'key1': 'value1', 'key2': 'value2'}&nbsp; &nbsp; }&nbsp; &nbsp; return response@mock.patch('views.request.get')def test_get_data(request_get):&nbsp; &nbsp; response_mock = config_response_200_mock(request_get)&nbsp; &nbsp; arg1 = 'arg1'&nbsp; &nbsp; arg2 = None&nbsp; &nbsp; arg3 = 'arg3'&nbsp; &nbsp; stuff = get_data(arg1, arg2, arg3)您还可以在这样的函数中创建一个魔术模拟对象,然后将该函数传递给new_callableon mock.patch():def response_200_mock():&nbsp; &nbsp; get_mock = mock.MagicMock()&nbsp; &nbsp; response = get_mock.return_value&nbsp; &nbsp; response.status_code = 200&nbsp; &nbsp; response.json.return_value = {&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; 0: {'key1': 'value1', 'key2': 'value2'}&nbsp; &nbsp; }&nbsp; &nbsp; return get_mock@mock.patch('views.request.get', new_callable=response_200_mock)def test_get_data(request_get):&nbsp; &nbsp; arg1 = 'arg1'&nbsp; &nbsp; arg2 = None&nbsp; &nbsp; arg3 = 'arg3'&nbsp; &nbsp; stuff = get_data(arg1, arg2, arg3)无论哪种方式,用于修补的对象request.get都test_get_data作为参数传入。两种方法的演示(patch用作上下文管理器而不是装饰器,但原理是相同的:>>> def config_response_200_mock(request_get):...&nbsp; &nbsp; &nbsp;response = request_get.return_value...&nbsp; &nbsp; &nbsp;response.status_code = 200...&nbsp; &nbsp; &nbsp;response.json.return_value = {...&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0: {'key1': 'value1', 'key2': 'value2'}...&nbsp; &nbsp; &nbsp;}...&nbsp; &nbsp; &nbsp;return response...>>> with mock.patch('__main__.request.get') as request_get:...&nbsp; &nbsp; &nbsp;response_mock = config_response_200_mock(request_get)...&nbsp; &nbsp; &nbsp;arg1 = 'arg1'...&nbsp; &nbsp; &nbsp;arg2 = None...&nbsp; &nbsp; &nbsp;arg3 = 'arg3'...&nbsp; &nbsp; &nbsp;stuff = get_data(arg1, arg2, arg3)...>>> stuff'processed_response'>>> response_mock.json(){0: {'key1': 'value1', 'key2': 'value2'}}>>> request_get.mock_calls[call('some_url?arg1&arg3')]>>> def response_200_mock():...&nbsp; &nbsp; &nbsp;get_mock = mock.MagicMock()...&nbsp; &nbsp; &nbsp;response = get_mock.return_value...&nbsp; &nbsp; &nbsp;response.status_code = 200...&nbsp; &nbsp; &nbsp;response.json.return_value = {...&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0: {'key1': 'value1', 'key2': 'value2'}...&nbsp; &nbsp; &nbsp;}...&nbsp; &nbsp; &nbsp;return get_mock...>>> with mock.patch('__main__.request.get', new_callable=response_200_mock) as request_get:...&nbsp; &nbsp; &nbsp;arg1 = 'arg1'...&nbsp; &nbsp; &nbsp;arg2 = None...&nbsp; &nbsp; &nbsp;arg3 = 'arg3'...&nbsp; &nbsp; &nbsp;stuff = get_data(arg1, arg2, arg3)...>>> stuff'processed_response'>>> request_get.return_value.json(){0: {'key1': 'value1', 'key2': 'value2'}}>>> request_get.mock_calls[call('some_url?arg1&arg3')]

慕婉清6462132

首先,非常感谢@Ja8zyjits 和@Martijn Pieters 的帮助。对我有用的解决方案如下:@mock.patch('request.get', side_effect=mock_response_200)def test_get_data(mock_get):&nbsp; &nbsp; arg1 = 'arg1'&nbsp; &nbsp; arg2 = None&nbsp; &nbsp; arg3 = 'arg3'&nbsp; &nbsp; expected_url = 'some_url?arg1&arg3'&nbsp; &nbsp; stuff = get_data(arg1, arg2, arg3)&nbsp; &nbsp; mock_get.assert_called_with(url)我不能说我完全理解传递mock_response_200为'side_effect'和传递mock_get到之间的相互作用test_get_data。但是使用这种组合,我能够同时断言打补丁的 request.get 的输入并返回所需的响应,以防止在响应处理期间引发任何错误。

慕标5832272

单元测试是一次测试一个基本组件。因此,内部调用的每个其他组件都需要在其他测试中进行测试。如果您只想断言url正确传递,那么我建议不要使用new关键字@mock.patch('module.process_response')@mock.patch('module.request.get')def test_get_data(mock_get, mock_process_response):&nbsp; &nbsp; arg1 = 'arg1'&nbsp; &nbsp; arg2 = None&nbsp; &nbsp; arg3 = 'arg3'&nbsp; &nbsp; url = "what ever url"&nbsp; &nbsp; stuff = get_data(arg1, arg2, arg3)&nbsp; &nbsp; mock_get.assert_called_with(url)这将帮助您确定它是否被正确调用。在后面的测试中,使用new关键字来检查返回的响应是否正确处理。这mock_process_response是一个MagicMock对象,将阻止process_response被调用,因此不需要mock_get定义json或被status_code定义。编辑:为process_response.
随时随地看视频慕课网APP

相关分类

Python
我要回答