How to mock up one method in a module other than mock up the whole module

My purpose is to mock up the return value of utcnow. I am using pytest and pretty new on it.

The method in my_file.py and under module my_module:

import datetime

def get_date_info() -> Tuple[int, str]:
    now_epoch = int(datetime.utcnow().strftime("%s"))
    # do something with now_epoch
    calculated_epoch = ...

    # another variable relies on datetime
    another_variable = datetime.fromtimestamp(calculated_epoch).strftime("%H")
return (now_epoch, another_variable)

My pytest test for the method:

from my_module.my_file import get_date_info
import datetime
import mock

@mock.patch("my_module.my_file.datetime")
def test_get_date_info():
        mock_dt.utcnow = mock.Mock(return_value=datetime.datetime(2002, 1, 1))
        actual_epoch, actual_another_variable = get_date_info()
        # assert code here 

The returned actual_epoch is accurate with the mocked date, unfortunately the below code didn't return str but <MagicMock name='datetime.fromtimestamp().strftime()' id='140249763149088'>

datetime.fromtimestamp(calculated_epoch).strftime("%H")

Does anyone know what causes the issue and how can I fix it?


Solution 1:

The issue is you are mocking only utcnow, so when utcnow is invoked in the actual code - it returns your mocked value. You have to mock datetime.fromtimestamp as well for it to return your mocked value. eg:

mock_dt.fromtimestamp = mock.Mock(return_value=datetime.datetime(2002, 1, 1))