Modifying 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 the response of request.post in the second iteration of the loop. From 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 this only works for one status_code. I looked at side_effect and it looks like I can iterate over the loop this way:
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 is not actually getting the "correct" status code. What's the best way to change the behavior in side_effect or return_value in order to get the behavior I want correctly? I think side_effect is what I want, but I'm not sure if the best way is to mock the answers.
source to share
An easier and more straightforward way to do it
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
an object MagicMock(side_effect=mock_responses)
and replace the link mymodule.requests.post
. You can also use mock_post
to test calls post()
like this:
mock_post.assert_has_calls([mock.call(first_url, first_params), mock.call(second_url, second_params)])
You can do the same job with build and configure mock_post
before and then pass it as a parameter new
(second argument patch
), but this way you have 2 disadvantages
- More code to write
- Can't use options
autospec=True
inpatch
Autospeccing is a very powerful framework feature mock
that prevents many silly bugs in both test and code.
source to share