使用mock

时间:2015-04-28 16:07:44

标签: 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

我想要做的是在循环的第二次迭代中更改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就是我想要的,但我不确定最好的方法是模拟回复。

2 个答案:

答案 0 :(得分:2)

更简单,更清洁的方法是

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
  3. 中失去使用patch选项的功能

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

答案 1 :(得分: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()