【问题标题】:Changing the second result of a function call with mock使用 mock 更改函数调用的第二个结果
【发布时间】:2015-04-28 16:07:43
【问题描述】:

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

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


    【解决方案1】:

    更简单更干净的方法是

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

    patch 通过MagicMock(side_effect=mock_responses) 创建mock_post 对象并替换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 参数)传递来完成相同的工作,但这样您有两个缺点

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

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

    【讨论】:

      【解决方案2】:

      其实很简单:

      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()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多