I am a little confused about the usage of patch
and of its arguments: new
and side_effect
(although this is not a proper argument of patch
but is passed to the created MagicMock).
When should I use or the other? or both possibly?
In my case, I can achieve my intended mocking with either method.
In this case, I was mocking the get response to an external api, the classic of the classic. I exemplified this here in this barebones module:
# src/module.py
class API:
def get():
return {"actual request": True} # assume this were making an actual request
def function_with_api_get_request():
api = API()
resp = api.get()
if resp['actual request']:
return 0
else:
return 1
new
from unittest.mock import patch
from src.module import function_with_api_get_request
expected_if_correct_mocking = 1
def mock_get_request(*args) -> dict:
print(f"I am a mocked API.get, called with args {args}.")
return {"actual request": False}
@patch("src.module.API.get", new=mock_get_request)
def test_function_with_api_get_request():
actual = function_with_api_get_request()
assert actual == expected_if_correct_mocking
When using new, I am telling patch
which object I want to use to substitute the target object. Interestingly, I noted here that the Mocked object is passed as first argument to the mock_get_request function. Its type is that of the object being mocked (I was expecting this to be MagicMock instead! why is it so?).
output
I am a mocked API.get, called with args (<src.module.API object at 0x7f01046ddc70>,).
side_effect
from unittest.mock import patch
from src.module import function_with_api_get_request
expected_if_correct_mocking = 1
def mock_get_request(*args) -> dict:
print(f"I am a mocked API.get, called with args {args}.")
return {"actual request": False}
@patch("src.module.API.get", side_effect=mock_get_request)
def test_function_with_api_get_request(mocked):
actual = function_with_api_get_request()
assert actual == expected_if_correct_mocking
When using side_effect, as per documentation, the Mock is passed to the decorated function. I achieve the same behaviour.
output
I am a mocked API.get, called with args ().
The question is: isn’t the point of side_effect
of actually doing something else, as the name also suggests? Maybe it’s totally fine and I am nitpicking.
What are then the cases where one would choose new
over side_effect
? are there use cases for and can they be used together?