I'm trying to patch two properties from a class but the mocking is returning a MagicMock instead the expected return value (String).
Client class:
class ClientApi:
def create_path(self):
return f"client_api_{self.time_now}T{self.date_now}.json"
@property
def date_now(self):
return datetime.now().strftime("%Y-%m-%d")
@property
def time_now(self):
return datetime.now().strftime("%H:%M:%S")
Test Class
class TestClientApi:
@pytest.fixture
def setup_class(self):
yield ClientApi()
def test_create_path(self, setup_class):
with patch("client_api.ClientApi.date_now") as mock_date_now, \
patch(client_api.ClientApi.time_now") as mock_time_now:
mock_date_now.return_value = "2023-11-28"
mock_time_now.return_value = "00:00:00"
expected_path = "client_api_2023-11-28T00:00:00.json"
assert expected_path = setup_class.create_path()
The create_path method is returning "<MagicMock name='time_now' id='1687227445600'>T<MagicMock name='date_now' id='1687227461936'>.json"
and I would like to understand why.
I would like to ask as well if anyone know how can I compress the two patches in one and if it will work, for example:
def test_create_path(self, setup_class):
with patch("client_api.ClientApi") as mock_client_api:
mock_client_api.return_value.date_now.return_value = "2023-11-28"
mock_client_api.return_value.time_now.return_value = "00:00:00"
Or any similar way, but it's not mocking it and just sending the current timestamp.
Thank you in advance
When you make an instance method a property it becomes a descriptor instance and is no longer a callable, so you cannot patch the descriptor instance with a mock object and still expect it to behave like a descriptor and automatically call its underlying getter function for you.
Since a property behaves like an instance attribute, you can simply use patch.multiple
instead to replace the two properties with the mock values you want:
with patch.multiple(ClientApi, date_now="2023-11-28", time_now="00:00:00"):
expected_path = "client_api_2023-11-28T00:00:00.json"
assert expected_path = setup_class.create_path()