How to mock python's datetime.now() in a class method for unit testing?
You could use freezegun :
from freezegun import freeze_timedef test(): assert datetime.datetime.now() != datetime.datetime(2012, 1, 14) with freeze_time("2012-01-14"): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) assert datetime.datetime.now() != datetime.datetime(2012, 1, 14)
It basically mocks datetime
module calls.
You'd create a function that returns a specific datetime, localized to the timezone passed in:
import mockdef mocked_get_now(timezone): dt = datetime.datetime(2012, 1, 1, 10, 10, 10) return timezone.localize(dt)@mock.patch('path.to.your.models.MyClass.get_now', side_effect=mocked_get_now)def your_test(self, mock_obj): # Within this test, `MyClass.get_now()` is a mock that'll return a predictable # timezone-aware datetime object, set to 2012-01-01 10:10:10.
That way you can test if the resulting timezone-aware datetime is correctly being handled; results elsewhere should show the correct timezone but will have a predictable date and time.
You use the mocked_get_now
function as a side-effect when mocking get_now
; whenever code calls get_now
the call is recorded by mock
, and mocked_get_now
is called, and it's return value used as the value returned to the caller of get_now
.
I'm using date
, but the same idea should work for datetime
:
class SpoofDate(date): def __new__(cls, *args, **kwargs): return date.__new__(date, *args, **kwargs)
...
from mock import patch@patch('some.module.date', SpoofDate)def testSomething(self): SpoofDate.today = classmethod(lambda cls : date(2012, 9, 24))
Where some.module
imports date
. Patch is replacing the imported date
with SpoofDate
, which you can then redefine to do whatever you want.