I am testing a method, geodata_collect._request_loc_data()
, and within that method I call another method, geodata_collect.utils.loadJSON(...)
which I need to mock in order to unit-test the first mentioned method.
My problem is that I need geodata_collect.utils.loadJSON(...)
to return a different value the third time it is called from within geodata_collect._request_loc_data()
.
I have been exploring MagicMock
and side_effect
in order to do this.
mock = MagicMock()
mock.side_effect = [self._create_request_dict(next_page_token=True),
self._create_request_dict(next_page_token=True), self._create_request_dict()]
with patch('geodata_collect.utils.loadJSON',return_value=mock):
geodata_collect._request_loc_data()
However, when geodata_collect.utils.loadJSON(...)
is called from within geodata_collect._request_loc_data()
the MagicMock class is returned, instead of the actual value.
<MagicMock id='140642209064888'>
What should be returned:
{'status': 'OK', 'next_page_token': 'Next Page EXISTS!!', 'result': [1, 2, 3, 4, 5]}
{'status': 'OK', 'next_page_token': 'Next Page EXISTS!!', 'result': [1, 2, 3, 4, 5]}
{'status': 'OK', 'result': [1, 2, 3, 4, 5]}
You have set the return value of the call to a mock object. So that’s what will be returned! You set return values (side effects) for calls to that call result, so geodata_collect.utils.loadJSON()()
.
Set the side_effect
argument in the patch()
call:
results = [
self._create_request_dict(next_page_token=True),
self._create_request_dict(next_page_token=True),
self._create_request_dict()]
with patch('geodata_collect.utils.loadJSON', side_effect=results):
geodata_collect._request_loc_data()
Or the side_effect
attribute on the mock object returned when entering the context manager:
with patch('geodata_collect.utils.loadJSON', side_effect=results) as load_mock:
load_mock.side_effect = [
self._create_request_dict(next_page_token=True),
self._create_request_dict(next_page_token=True),
self._create_request_dict()]
geodata_collect._request_loc_data()
Capturing the mock object the patch()
context manager creates with as <name>
is generally a good idea anyway as you now have access to it to assert if it was called.
You can also pass in the MagicMock
instance you created up front, just pass it in as the second argument, or use the name new
:
mock = MagicMock()
mock.side_effect = [self._create_request_dict(next_page_token=True),
self._create_request_dict(next_page_token=True), self._create_request_dict()]
with patch('geodata_collect.utils.loadJSON', mock): # or new=mock
geodata_collect._request_loc_data()
patch()
will then replace geodata_collect.utils.loadJSON
with that instance, and calling it will use the side_effect
list set.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With