3 回答
TA贡献1820条经验 获得超10个赞
您正在修补模块中的未知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):
response = request_get.return_value
response.status_code = 200
response.json.return_value = {
0: {'key1': 'value1', 'key2': 'value2'}
}
return response
@mock.patch('views.request.get')
def test_get_data(request_get):
response_mock = config_response_200_mock(request_get)
arg1 = 'arg1'
arg2 = None
arg3 = 'arg3'
stuff = get_data(arg1, arg2, arg3)
您还可以在这样的函数中创建一个魔术模拟对象,然后将该函数传递给new_callableon mock.patch():
def response_200_mock():
get_mock = mock.MagicMock()
response = get_mock.return_value
response.status_code = 200
response.json.return_value = {
0: {'key1': 'value1', 'key2': 'value2'}
}
return get_mock
@mock.patch('views.request.get', new_callable=response_200_mock)
def test_get_data(request_get):
arg1 = 'arg1'
arg2 = None
arg3 = 'arg3'
stuff = get_data(arg1, arg2, arg3)
无论哪种方式,用于修补的对象request.get都test_get_data作为参数传入。
两种方法的演示(patch用作上下文管理器而不是装饰器,但原理是相同的:
>>> def config_response_200_mock(request_get):
... response = request_get.return_value
... response.status_code = 200
... response.json.return_value = {
... 0: {'key1': 'value1', 'key2': 'value2'}
... }
... return response
...
>>> with mock.patch('__main__.request.get') as request_get:
... response_mock = config_response_200_mock(request_get)
... arg1 = 'arg1'
... arg2 = None
... arg3 = 'arg3'
... 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():
... get_mock = mock.MagicMock()
... response = get_mock.return_value
... response.status_code = 200
... response.json.return_value = {
... 0: {'key1': 'value1', 'key2': 'value2'}
... }
... return get_mock
...
>>> with mock.patch('__main__.request.get', new_callable=response_200_mock) as request_get:
... arg1 = 'arg1'
... arg2 = None
... arg3 = 'arg3'
... 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')]
TA贡献1804条经验 获得超2个赞
首先,非常感谢@Ja8zyjits 和@Martijn Pieters 的帮助。
对我有用的解决方案如下:
@mock.patch('request.get', side_effect=mock_response_200)
def test_get_data(mock_get):
arg1 = 'arg1'
arg2 = None
arg3 = 'arg3'
expected_url = 'some_url?arg1&arg3'
stuff = get_data(arg1, arg2, arg3)
mock_get.assert_called_with(url)
我不能说我完全理解传递mock_response_200为'side_effect'和传递mock_get到之间的相互作用test_get_data。但是使用这种组合,我能够同时断言打补丁的 request.get 的输入并返回所需的响应,以防止在响应处理期间引发任何错误。
TA贡献1966条经验 获得超4个赞
单元测试是一次测试一个基本组件。因此,内部调用的每个其他组件都需要在其他测试中进行测试。
如果您只想断言url正确传递,那么我建议不要使用new关键字
@mock.patch('module.process_response')
@mock.patch('module.request.get')
def test_get_data(mock_get, mock_process_response):
arg1 = 'arg1'
arg2 = None
arg3 = 'arg3'
url = "what ever url"
stuff = get_data(arg1, arg2, arg3)
mock_get.assert_called_with(url)
这将帮助您确定它是否被正确调用。在后面的测试中,使用new关键字来检查返回的响应是否正确处理。
这mock_process_response是一个MagicMock对象,将阻止process_response被调用,因此不需要mock_get定义json或被status_code定义。
编辑:为process_response.
添加回答
举报