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.
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
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.