Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing the second result of a function call with mock

I have a loop that looks like this:

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

What I would like to do is change response of requests.post in the second iteration of the loop. From within my test, I know I can do something like:

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

But that only seems to work for one status_code. I looked at side_effect, and it looks like I can iterate through the loop like so:

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

However, it looks like it doesn't actually get the "right" status code. What's the best way of changing the behavior in side_effect or return_value to properly get the behavior I want? I think side_effect is what I want, but I'm not sure what the best way is to mock the responses.

like image 855
TJ1S Avatar asked Apr 28 '15 16:04

TJ1S


2 Answers

The simpler and cleaner way to do it is

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

patch create mock_post object by MagicMock(side_effect=mock_responses) and replace mymodule.requests.post reference. You can also use mock_post to check post() calls by something like:

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

You can do the same work by build and configure mock_post before and then pass it as new parameter (the second patch argument) but by this way you have 2 downside

  1. More code to write
  2. Lose the ability to use autospec=True options in patch

Autospeccing is a very powerful feature of mock framework that prevent a lot of silly bug both in test and code.

like image 93
Michele d'Amico Avatar answered Oct 05 '22 08:10

Michele d'Amico


Actually turns out it was as simple as:

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()
like image 45
TJ1S Avatar answered Oct 05 '22 08:10

TJ1S