使用mock更改函数调用的第二个结果

问题描述 投票:0回答:3

我有一个看起来像这样的循环:

for i in range(len(some_list)):
    response = requests.post(some_url, some_params)
    if response.status_code != HTTPOk:
       # do something

我想做的是在循环的第二次迭代中更改 requests.post 的响应。从我的测试中,我知道我可以做类似的事情:

mock_response = mock.Mock()
mock_response.status_code = 404
with mock.patch(mymodule.requests.post, return_value=mock_response):
   mymodule.some_function()

但这似乎只适用于一个 status_code。我查看了side_effect,看起来我可以像这样迭代循环:

mock_response.side_effect = [
    mock.Mock(status_code=400), mock.Mock(status_code=200)
]
with mock.patch(mymodule.requests.post, return_value=mock_response):
   mymodule.some_function()

但是,看起来它实际上并没有获得“正确”的状态代码。更改 side_effect 或 return_value 中的行为以正确获得我想要的行为的最佳方法是什么?我认为 side_effect 是我想要的,但我不确定模拟响应的最佳方法是什么。

python mocking pytest python-mock
3个回答
4
投票

更简单、更干净的方法是

with mock.patch("mymodule.requests.post", 
                side_effect=[Mock(status_code=400), Mock(status_code=200)]) as mock_post:
   mymodule.some_function()

patch
通过
mock_post
创建
MagicMock(side_effect=mock_responses)
对象并替换
mymodule.requests.post
引用。您还可以使用
mock_post
来检查
post()
调用,例如:

mock_post.assert_has_calls([mock.call(first_url, first_params), mock.call(second_url, second_params)])

您可以通过之前构建和配置

mock_post
来完成相同的工作,然后将其作为
new
参数(第二个
patch
参数)传递,但通过这种方式,您有 2 个缺点

  1. 还有更多代码需要编写
  2. 失去使用
    autospec=True
     中的 
    patch
  3. 选项的能力

Autospeccing

mock
框架的一个非常强大的功能,可以防止测试和代码中出现很多愚蠢的错误。


1
投票

事实上,事情很简单:

mock_response.side_effect = [
    mock.Mock(status_code=400), mock.Mock(status_code=200)
]
with mock.patch(mymodule.requests.post, mock_response):
   mymodule.some_function()

0
投票

如果你想每次都有不同的 json 正文:

with mock.patch("mymodule.requests.post",
                    side_effect=[
                        Mock(status_code=400,
                        json=Mock(return_value=json_goes_here)),
                        Mock(status_code=200,
                        json=Mock(return_value=different_json_goes_here))]) as mock_post:
        mymodule.some_function()
© www.soinside.com 2019 - 2024. All rights reserved.