I\'m trying to write tests for a class that has methods like:
import datetime
import pytz
class MyClass:
def get_now(self, timezone):
return dat
If you don't want to install anything this is the simplest way. Simply use, Mock class -
class NewDt(datetime.date):
@classmethod
def now(cls):
return datetime.datetime.strptime('2020-07-10 05:20:20', '%Y-%m-%d %H:%M:%S')
And use this patch before mock function
@mock.patch('module path', NewDt)
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.
Having asked this question originally...
As @Jocelyn delalande suggested, I've been happily using freezegun for years now.
Another option is python-libfaketime, which can be much faster than freezegun, but doesn't work on Windows and sounds a bit fiddly.
A newer option is time-machine, introduced in this blog post that compares the three options.
You'd create a function that returns a specific datetime, localized to the timezone passed in:
import mock
def 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
.
Using patch of unittest.mock
from unittest.mock import patch
@patch('MyClass.datetime')
def test_foo(self, mock_datetime):
mock_datetime.datetime.now.return_value = datetime.datetime(2019, 5, 7) #SOME_MOCKED_DATE
Note that we're overriding datetime module that is imported only in our class
The class for which we are writing the test:
import datetime
class MyClass:
def foo():
localtime_now = datetime.datetime.now(timezone)
We need not have to separate it as get_now() method just to make it easier to mock.
You could use freezegun :
from freezegun import freeze_time
def 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.