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

TJ1*_*J1S 7 python mocking pytest python-mock

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

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

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

mock_response = mock.Mock()
mock_response.status_code = 404
with mock.patch(mymodule.requests.post, return_value=mock_response):
   mymodule.some_function()
Run Code Online (Sandbox Code Playgroud)

但这似乎只适用于一个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()
Run Code Online (Sandbox Code Playgroud)

但是,看起来它实际上并没有获得"正确"的状态代码.更改side_effect或return_value中的行为以正确获取我想要的行为的最佳方法是什么?我认为side_effect就是我想要的,但我不确定最好的方法是嘲笑回应.

Mic*_*ico 4

更简单、更干净的方法是

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

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)])
Run Code Online (Sandbox Code Playgroud)

您可以通过之前的构建和配置来完成相同的工作,mock_post然后将其作为new参数(第二个patch参数)传递,但通过这种方式您有两个缺点

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

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