Appengine datastore raising badValueErro on datetime, might be caused by monkeypatch - python

I'm getting the following error message:
BadValueError: Expected datetime, got datetime.datetime(2013, 4, 19, 19, 48, 2, 566558)
The error is raised in ndb's model.py line 1190, here's a snippet of code in there.
def _validate(self, value):
if not isinstance(value, datetime.datetime):
raise datastore_errors.BadValueError('Expected datetime, got %r' % (value,))
This DateTime is Passed into a model like this:
#user is a parameter that's passed into the function this code is inside
#the same goes for lifetime, which is a number of seconds
token = os.urandom(16).encode("hex")
expires=datetime.datetime.now() + datetime.timedelta(seconds=lifetime)
instance = cls(token=token, user=user, expires=expires)
However, I'm monkeypatching datetime.datetime using pytest's monkeypatch argument.
newnow = datetime.datetime.now()
later = newnow + datetime.timedelta(seconds=10)
class fake_dt(datetime.datetime):
#classmethod
def now(cls):
return newnow
monkeypatch.setattr(datetime,"datetime", fake_dt)
#after that, I call my model creation function for the test.
Could the fact that I'm monkeypatching datetime.datetime be the problem? and how do I get around that? I need to make sure that datetime.datetime.now() returns the date I captured at the start of my test.

Related

Force aware time in python

Is there any way to force all time objects in Python
to be aware, perhaps generating an error if I try to
generate a naïve object?
Is there a way to tell whether a time object is naïve?
Trusting code to be non-naïve is not working for me
and I'm getting bitten.
To tell if a datetime object is aware check its tzinfo attribute, as per the datetime doc says:
A datetime object d is aware if both of the following hold:
d.tzinfo is not None
d.tzinfo.utcoffset(d) does not return None
Otherwise, d is naive.
A time object t is aware if both of the following hold:
t.tzinfo is not None
t.tzinfo.utcoffset(None) does not return None.
As to how to force all datetimes to not be naive, there is a problem. Sometimes one simply does not have the timezone info.
Why not override datetime.datetime.__new__ in a subclass?
Notice how the method datetime.datetime.__new__ checks the timezone argument before creating new instances by calling the module level function:
# cpython/Lib/datetime.py
def _check_tzinfo_arg(tz):
if tz is not None and not isinstance(tz, tzinfo):
raise TypeError("tzinfo argument must be None or of a tzinfo subclass")
So we can invoke a similar check before calling datetime.datetime.__new__ in our subclass
import datetime
class AwareDate(datetime.datetime):
def __new__(cls, *args, **kwargs):
if not isinstance(kwargs.get('tzinfo', None), datetime.tzinfo):
raise ValueError('MUST BE TZ AWARE !')
return datetime.datetime.__new__(cls, *args, **kwargs)
Some quick tests
normaldate = datetime.datetime(2020, 12, 20, tzinfo=datetime.timezone.utc)
awaredate = AwareDate(2020, 12, 20, tzinfo=datetime.timezone.utc)
assert awaredate == normaldate
normaldate = datetime.datetime(2020, 12, 20)
awaredate = AwareDate(2020, 12, 20) # ValueError: MUST BE TZ AWARE!

python - property() in a Class use problem, setter shows TypeError

I'm coding a pybite on codechalleng.es and totally run out of ideas.
Problem is as follows:
task description
I need to write a class that returns boolean True/False whether the promotion has expired or not.
It's tested by invoking a property getter promotion.expired (see tests at the very end)
from datetime import datetime, timedelta
NOW = datetime.now() # defined here for test compatilibity (time)
class Promo:
""" docstring hehe"""
def __init__(self, name, expires):
self.name = name
self.setpromo(expires)
def checkpromo(self):
return self.expired
def setpromo(self, value):
self.expired = value < datetime.now()
expired = property(checkpromo, setpromo)
test_time = NOW + timedelta(days=1)
promotion_10 = Promo('promotion 10%', test_time)
Now it throws an error where i can't compare value in setter vs. datetime object. In my opinion as we pass test_time (a datetime object) into setter, it should be able to compare datetime vs. datetime - instead the program says it's a bool. Not sure how to proceed. Thank you for any insight.
Traceback (most recent call last):
File "/tmp/simple_property.py", line 24, in <module>
promotion_10 = Promo('promotion 10%', test_time)
File "/tmp/simple_property.py", line 10, in __init__
self.setpromo(expires)
File "/tmp/simple_property.py", line 17, in setpromo
self.expired = value < datetime.now()
File "/tmp/simple_property.py", line 17, in setpromo
self.expired = value < datetime.now()
TypeError: '<' not supported between instances of 'bool' and 'datetime.datetime'
tests that needs to pass:
from datetime import timedelta
import inspect
from simple_property import Promo, NOW
def test_promo_expired():
past_time = NOW - timedelta(seconds=3)
twitter_promo = Promo('twitter', past_time)
assert twitter_promo.expired
def test_promo_not_expired():
future_date = NOW + timedelta(days=1)
newsletter_promo = Promo('newsletter', future_date)
assert not newsletter_promo.expired
def test_uses_property():
assert 'property' in inspect.getsource(Promo)
I've finally found the issue - it might be interesting to someone experiencing such setter/property() behaviour. (Please correct me if im not supposed to answer my own question/close the topic etc.)
In my example, the property expired has the same name as private attribute self.expired.
After changing the code to (just adding one underscore in self._expired - changing the name so it does not overlap with property() name):
def checkpromo(self):
return self._expired
def setpromo(self, value):
self._expired = value < datetime.now()
It's worked! thank you
EDIT - adding elegant decorator way of solving the task (provided as an answer once submitted my task to codechalleng.es)
from datetime import datetime
NOW = datetime.now()
class Promo:
def __init__(self, name, expires=NOW):
self.name = name
self.expires = expires
#property
def expired(self):
return datetime.now() > self.expires

Would the same chain of calls on a mock always return the exact same mock object?

Code:
from unittest.mock import Mock
mock = Mock()
print('mock.f():', id(mock.f()))
print('mock.f().g().h():', id(mock.f().g().h()))
print('mock():', id(mock()))
print('mock().f():', id(mock().f()))
print()
print('mock.f():', id(mock.f()))
print('mock.f().g().h():', id(mock.f().g().h()))
print('mock():', id(mock()))
print('mock().f():', id(mock().f()))
print()
print('mock.f(1):', id(mock.f(1)))
print('mock.f(2).g(3).h(4):', id(mock.f(2).g(3).h(4)))
print('mock(5):', id(mock(5)))
print('mock(6).f(7):', id(mock(6).f(7)))
print()
Output:
mock.f(): 4483288208
mock.f().g().h(): 4483354192
mock(): 4483368976
mock().f(): 4483708880
mock.f(): 4483288208
mock.f().g().h(): 4483354192
mock(): 4483368976
mock().f(): 4483708880
mock.f(1): 4483288208
mock.f(2).g(3).h(4): 4483354192
mock(5): 4483368976
mock(6).f(7): 4483708880
Observation:
The output shows that a specified chained function call on a mock always returns the same object within the lifetime of a program regardless of how many times we make that call.
For example, the first call to mock.f().g().h(), the second call to mock.f().g().h(), and even the third call with different arguments mock.f(2).g(3).h(4) return the exact same object.
Question:
Can we rely on this behavior? Is it guaranteed that within the lifetime of a program, mock.f().g().h() would return the exact same mock object?
Is it guaranteed that even the same chain of calls with different arguments, e.g., mock.f(2).g(3).h(4) would also return the same object as a mock.f().g().h()?
Are both these things documented somewhere?
Background:
The reason why I am asking this is so that instead of writing code like this:
from urllib import request
from unittest.mock import Mock, patch
with patch('urllib.request.urlopen') as mock_urlopen:
mock_urlopen.return_value = Mock()
mock_urlopen().getcode.return_value = 200
assert request.urlopen('').getcode() == 200
I can write code like this insted:
from urllib import request
from unittest.mock import Mock, patch
with patch('urllib.request.urlopen') as mock_urlopen:
mock_urlopen().getcode.return_value = 200
assert request.urlopen('').getcode() == 200
The examples above are too simple only for demo purpose. I wanted to keep self-contained examples. But if I could rely on this feature, it would become very convenient when the chain of function calls are long. That's why I am looking for some sort of reference or documentation that shows that I can rely on this behavior.
If you look at the file lib/python3.7/unittest/mock.py
def __getattr__(self, name):
if name in {'_mock_methods', '_mock_unsafe'}:
raise AttributeError(name)
elif self._mock_methods is not None:
if name not in self._mock_methods or name in _all_magics:
raise AttributeError("Mock object has no attribute %r" % name)
elif _is_magic(name):
raise AttributeError(name)
if not self._mock_unsafe:
if name.startswith(('assert', 'assret')):
raise AttributeError(name)
result = self._mock_children.get(name)
if result is _deleted:
raise AttributeError(name)
elif result is None:
wraps = None
if self._mock_wraps is not None:
# XXXX should we get the attribute without triggering code
# execution?
wraps = getattr(self._mock_wraps, name)
result = self._get_child_mock(
parent=self, name=name, wraps=wraps, _new_name=name,
_new_parent=self
)
self._mock_children[name] = result
elif isinstance(result, _SpecState):
result = create_autospec(
result.spec, result.spec_set, result.instance,
result.parent, result.name
)
self._mock_children[name] = result
return result
As you can see the object is cached in _mock_children dict. And hence every call will return you the object. But the data will be updated. That you can see by running below code
from unittest.mock import Mock
mock = Mock()
mock.a(10)
mock.a.assert_called_with(10)
mock.a(2)
mock.a.assert_called_with(10)
and the result
Traceback (most recent call last):
File ".../workbench.py", line 8, in <module>
mock.a.assert_called_with(10)
File ....lib/python3.7/unittest/mock.py", line 834, in assert_called_with
raise AssertionError(_error_message()) from cause
AssertionError: Expected call: a(10)
Actual call: a(2)
So, yes the object will be same, but the object will have updated values

Mock datetime.datetime.now() while unit testing

#pytest.mark.parametrize("test_input,expected_output", data)
def test_send_email(test_input, expected_output):
emails = SendEmails(email_client=MagicMock())
emails.send_email = MagicMock()
emails.send_new_email(*test_input)
emails.send_email.assert_called_with(*expected_output)
I am looking to mock datetime.datetime.now() which is called in the send_new_email method. I am unsure how to do it however.
I tried creating a new datetime object
datetime_object = datetime.datetime.strptime('Jun 1 2017 1:33PM',
'%b %d %Y %I:%M%p')
and then overriding datetime.datetime.now
datetime.datetime.now = MagicMock(return_value=datetime_object)
However, I get the error
TypeError: can't set attributes of built-in/extension type 'datetime.datetime'
This question was marked as duplicate of Python: Trying to mock datetime.date.today() but not working
Python: Trying to mock datetime.date.today() but not working
I had already tried this solution but I could not get it to work. I cannot install freezegun due to the project requirements.
I have created a new class in the test file
class NewDate(datetime.date):
#classmethod
def today(cls):
return cls(2010, 1, 1)
datetime.date = NewDate
But I have no idea how to get the SendEmails class to use this.
You could replace the whole class:
_FAKE_TIME = 0
class _FakeDateTime(datetime.datetime):
#staticmethod
def now():
return _FAKE_TIME
then to use it:
_FAKE_TIME = whatever
datetime.datetime = _FakeDateTime
The class needs some refinements like comparison operators to make a FakeDateTime comparable to a datetime, but it should work.

Trying to mock datetime.date.today(), but not working

Can anyone tell me why this isn't working?
>>> import mock
>>> #mock.patch('datetime.date.today')
... def today(cls):
... return date(2010, 1, 1)
...
>>> from datetime import date
>>> date.today()
datetime.date(2010, 12, 19)
Perhaps someone could suggest a better way?
Another option is to use
https://github.com/spulec/freezegun/
Install it:
pip install freezegun
And use it:
from freezegun import freeze_time
#freeze_time("2012-01-01")
def test_something():
from datetime import datetime
print(datetime.now()) # 2012-01-01 00:00:00
from datetime import date
print(date.today()) # 2012-01-01
It also affects other datetime calls in method calls from other modules:
other_module.py:
from datetime import datetime
def other_method():
print(datetime.now())
main.py:
from freezegun import freeze_time
#freeze_time("2012-01-01")
def test_something():
import other_module
other_module.other_method()
And finally:
$ python main.py
# 2012-01-01
For what it's worth, the Mock docs talk about datetime.date.today specifically, and it's possible to do this without having to create a dummy class:
https://docs.python.org/3/library/unittest.mock-examples.html#partial-mocking
>>> from datetime import date
>>> with patch('mymodule.date') as mock_date:
... mock_date.today.return_value = date(2010, 10, 8)
... mock_date.side_effect = lambda *args, **kw: date(*args, **kw)
...
... assert mymodule.date.today() == date(2010, 10, 8)
... assert mymodule.date(2009, 6, 8) == date(2009, 6, 8)
...
There are a few problems.
First of all, the way you're using mock.patch isn't quite right. When used as a decorator, it replaces the given function/class (in this case, datetime.date.today) with a Mock object only within the decorated function. So, only within your today() will datetime.date.today be a different function, which doesn't appear to be what you want.
What you really want seems to be more like this:
#mock.patch('datetime.date.today')
def test():
datetime.date.today.return_value = date(2010, 1, 1)
print datetime.date.today()
Unfortunately, this won't work:
>>> test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "build/bdist.macosx-10.6-universal/egg/mock.py", line 557, in patched
File "build/bdist.macosx-10.6-universal/egg/mock.py", line 620, in __enter__
TypeError: can't set attributes of built-in/extension type 'datetime.date'
This fails because Python built-in types are immutable - see this answer for more details.
In this case, I would subclass datetime.date myself and create the right function:
import datetime
class NewDate(datetime.date):
#classmethod
def today(cls):
return cls(2010, 1, 1)
datetime.date = NewDate
And now you could do:
>>> datetime.date.today()
NewDate(2010, 1, 1)
I guess I came a little late for this but I think the main problem here is that you're patching datetime.date.today directly and, according to the documentation, this is wrong.
You should patch the reference imported in the file where the tested function is, for example.
Let's say you have a functions.py file where you have the following:
import datetime
def get_today():
return datetime.date.today()
then, in your test, you should have something like this
import datetime
import unittest
from functions import get_today
from mock import patch, Mock
class GetTodayTest(unittest.TestCase):
#patch('functions.datetime')
def test_get_today(self, datetime_mock):
datetime_mock.date.today = Mock(return_value=datetime.strptime('Jun 1 2005', '%b %d %Y'))
value = get_today()
# then assert your thing...
Hope this helps a little bit.
Here's another way to mock datetime.date.today() with an added bonus that the rest of datetime functions continue to work, as the mock object is configured to wrap the original datetime module:
from unittest import mock, TestCase
import foo_module
class FooTest(TestCase):
#mock.patch(f'{foo_module.__name__}.datetime', wraps=datetime)
def test_something(self, mock_datetime):
# mock only datetime.date.today()
mock_datetime.date.today.return_value = datetime.date(2019, 3, 15)
# other calls to datetime functions will be forwarded to original datetime
Note the wraps=datetime argument to mock.patch() – when the foo_module uses other datetime functions besides date.today() they will be forwarded to the original wrapped datetime module.
To add to Daniel G's solution:
from datetime import date
class FakeDate(date):
"A manipulable date replacement"
def __new__(cls, *args, **kwargs):
return date.__new__(date, *args, **kwargs)
This creates a class which, when instantiated, will return a normal datetime.date object, but which is also able to be changed.
#mock.patch('datetime.date', FakeDate)
def test():
from datetime import date
FakeDate.today = classmethod(lambda cls: date(2010, 1, 1))
return date.today()
test() # datetime.date(2010, 1, 1)
The easiest way for me is doing this:
import datetime
from unittest.mock import Mock, patch
def test():
datetime_mock = Mock(wraps=datetime.datetime)
datetime_mock.now.return_value = datetime.datetime(1999, 1, 1)
with patch('datetime.datetime', new=datetime_mock):
assert datetime.datetime.now() == datetime.datetime(1999, 1, 1)
CAUTION for this solution: all functionality from datetime module from the target_module will stop working.
I faced the same situation a couple of days ago, and my solution was to define a function in the module to test and just mock that:
def get_date_now():
return datetime.datetime.now()
Today I found out about FreezeGun, and it seems to cover this case beautifully
from freezegun import freeze_time
import datetime
import unittest
#freeze_time("2012-01-14")
def test():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
You can use the following approach, based on Daniel G solution. This one has advantage of not breaking type checking with isinstance(d, datetime.date).
import mock
def fixed_today(today):
from datetime import date
class FakeDateType(type):
def __instancecheck__(self, instance):
return isinstance(instance, date)
class FakeDate(date):
__metaclass__ = FakeDateType
def __new__(cls, *args, **kwargs):
return date.__new__(date, *args, **kwargs)
#staticmethod
def today():
return today
return mock.patch("datetime.date", FakeDate)
Basically, we replace C-based datetime.date class with our own python subclass, that produces original datetime.date instances and responds to isinstance() queries exactly as native datetime.date.
Use it as context manager in your tests:
with fixed_today(datetime.date(2013, 11, 22)):
# run the code under test
# note, that these type checks will not break when patch is active:
assert isinstance(datetime.date.today(), datetime.date)
Similar approach can be used to mock datetime.datetime.now() function.
CPython actually implements the datetime module using both a pure-Python Lib/datetime.py and a C-optimized Modules/_datetimemodule.c. The C-optimized version cannot be patched but the pure-Python version can.
At the bottom of the pure-Python implementation in Lib/datetime.py is this code:
try:
from _datetime import * # <-- Import from C-optimized module.
except ImportError:
pass
This code imports all the C-optimized definitions and effectively replaces all the pure-Python definitions. We can force CPython to use the pure-Python implementation of the datetime module by doing:
import datetime
import importlib
import sys
sys.modules["_datetime"] = None
importlib.reload(datetime)
By setting sys.modules["_datetime"] = None, we tell Python to ignore the C-optimized module. Then we reload the module which causes the import from _datetime to fail. Now the pure-Python definitions remain and can be patched normally.
If you're using Pytest then include the snippet above in conftest.py and you can patch datetime objects normally.
We can use pytest-mock (https://pypi.org/project/pytest-mock/) mocker object to mock datetime behaviour in a particular module
Let's say you want to mock date time in the following file
# File path - source_dir/x/a.py
import datetime
def name_function():
name = datetime.now()
return f"name_{name}"
In the test function, mocker will be added to the function when test runs
def test_name_function(mocker):
mocker.patch('x.a.datetime')
x.a.datetime.now.return_value = datetime(2019, 1, 1)
actual = name_function()
assert actual == "name_2019-01-01"
Generally speaking, you would have datetime or perhaps datetime.date imported into a module somewhere. A more effective way of mocking the method would be to patch it on the module that is importing it. Example:
a.py
from datetime import date
def my_method():
return date.today()
Then for your test, the mock object itself would be passed as an argument to the test method. You would set up the mock with the result value you want, and then call your method under test. Then you would assert that your method did what you want.
>>> import mock
>>> import a
>>> #mock.patch('a.date')
... def test_my_method(date_mock):
... date_mock.today.return_value = mock.sentinel.today
... result = a.my_method()
... print result
... date_mock.today.assert_called_once_with()
... assert mock.sentinel.today == result
...
>>> test_my_method()
sentinel.today
A word of warning. It is most certainly possible to go overboard with mocking. When you do, it makes your tests longer, harder to understand, and impossible to maintain. Before you mock a method as simple as datetime.date.today, ask yourself if you really need to mock it. If your test is short and to the point and works fine without mocking the function, you may just be looking at an internal detail of the code you're testing rather than an object you need to mock.
It's possible to mock functions from datetime module without adding side_effects
import mock
from datetime import datetime
from where_datetime_used import do
initial_date = datetime.strptime('2018-09-27', "%Y-%m-%d")
with mock.patch('where_datetime_used.datetime') as mocked_dt:
mocked_dt.now.return_value = initial_date
do()
The best approach for me is a combination of #Daniel G and #frx08 solutions:
class Test_mock_date:
class NewDate(datetime.datetime):
#classmethod
def now(cls, tz=None):
return cls(2021, 5, 12)
def test_mock_date(self):
with patch('datetime.datetime', new = self.NewDate):
assert datetime.datetime.now() == datetime.datetime(2021, 5, 12, 0, 0)
You can take a look at the following medium article I wrote with different examples about how to use MagicMock https://medium.com/#camposer/d2113513b365
For those of you using pytest with pytest-mock (more info on pytest-mock at the end) here is how I mocked datetime.datetime.now() which is very similar to the original question.
test_get_now(mocker):
datetime_mock = mocker.patch("blackline_accounts_import.datetime",)
datetime_mock.datetime.now.return_value=datetime.datetime(2019,3,11,6,2,0,0)
now == function_being_tested() # run function
assert now == datetime.datetime(2019,3,11,6,2,0,0)
Essentially the mock has to be set to return the specified date. You aren't able to patch over datetime's object directly.
Pytest-mock is a library that makes a mock object a fixture. More detail can be found here
Maybe you could use your own "today()" method that you will patch where needed. Example with mocking utcnow() can be found here: https://bitbucket.org/k_bx/blog/src/tip/source/en_posts/2012-07-13-double-call-hack.rst?at=default
I implemented #user3016183 method using a custom decorator:
def changeNow(func, newNow = datetime(2015, 11, 23, 12, 00, 00)):
"""decorator used to change datetime.datetime.now() in the tested function."""
def retfunc(self):
with mock.patch('mymodule.datetime') as mock_date:
mock_date.now.return_value = newNow
mock_date.side_effect = lambda *args, **kw: datetime(*args, **kw)
func(self)
return retfunc
I thought that might help someone one day...
Several solutions are discussed in http://blog.xelnor.net/python-mocking-datetime/. In summary:
Mock object - Simple and efficient but breaks isinstance() checks:
target = datetime.datetime(2009, 1, 1)
with mock.patch.object(datetime, 'datetime', mock.Mock(wraps=datetime.datetime)) as patched:
patched.now.return_value = target
print(datetime.datetime.now())
Mock class
import datetime
import mock
real_datetime_class = datetime.datetime
def mock_datetime_now(target, dt):
class DatetimeSubclassMeta(type):
#classmethod
def __instancecheck__(mcs, obj):
return isinstance(obj, real_datetime_class)
class BaseMockedDatetime(real_datetime_class):
#classmethod
def now(cls, tz=None):
return target.replace(tzinfo=tz)
#classmethod
def utcnow(cls):
return target
# Python2 & Python3 compatible metaclass
MockedDatetime = DatetimeSubclassMeta('datetime', (BaseMockedDatetime,), {})
return mock.patch.object(dt, 'datetime', MockedDatetime)
Use as:
with mock_datetime_now(target, datetime):
....
I made this work by importing datetime as realdatetime and replacing the methods I needed in the mock with the real methods:
import datetime as realdatetime
#mock.patch('datetime')
def test_method(self, mock_datetime):
mock_datetime.today = realdatetime.today
mock_datetime.now.return_value = realdatetime.datetime(2019, 8, 23, 14, 34, 8, 0)
You can mock datetime using this:
In the module sources.py:
import datetime
class ShowTime:
def current_date():
return datetime.date.today().strftime('%Y-%m-%d')
In your tests.py:
from unittest import TestCase, mock
import datetime
class TestShowTime(TestCase):
def setUp(self) -> None:
self.st = sources.ShowTime()
super().setUp()
#mock.patch('sources.datetime.date')
def test_current_date(self, date_mock):
date_mock.today.return_value = datetime.datetime(year=2019, month=10, day=1)
current_date = self.st.current_date()
self.assertEqual(current_date, '2019-10-01')
For those using patchers in a test class, here's how I'm successfully patching datetime functionality:
from datetime import datetime
import unittest
from unittest.mock import Mock, patch
# Replace with the proper path to the module you would
# like datetime to be mocked
from path.to.my_module
class MyTestCases(unittest.TestCase):
def setUp(self):
"""execute on class instantiation"""
# Record both times at the same moment
self.dt_now, self.dt_utcnow = datetime.now(), datetime.utcnow()
# After retrieving real (or hardcoded datetime values),
# proceed to mock them in desired module
self.patch_datetime_functions()
def patch_datetime_functions(self) -> None:
"""
Patch datetime.now() and datetime.utcnow() to prevent issues when
comparing expected dates
"""
# Create a patcher
self.patcher_dt = patch(
'path.to.my_module'
)
# Start but make sure cleanup always occurs
self.patcher_dt.start()
self.addCleanup(self.patcher_dt.stop)
# Perform the actual patch – use lambdas as mock functions
datetime_mock = Mock(wraps=datetime)
datetime_mock.now.return_value = self.dt_now
datetime_mock.utcnow.return_value = self.dt_utcnow
my_module.datetime = datetime_mock
# Here's what it will look like when testing:
def some_test(self):
curr_dt = self.dt_now
returned_dt = my_module.datetime.utcnow()
# Compare the dates
self.assertEqual(curr_dt, returned_dt,
'Datetime values should be equal'
)
Minimal working example with monkeypatch
This solution uses monkeypatch from the https://pypi.org/project/pytest-mock/ package.
Features:
mock only datetime.today(), but datetime.now() still works as expected
mock only in a specific scope (i.e. block)
import sys
from datetime import datetime
MOCKED_DATETIME_TODAY = datetime(1900, 1, 1, 0, 0, 0)
class MockedDatetime(datetime):
#classmethod
def today(cls):
return MOCKED_DATETIME_TODAY
def test_mock_datetime_today(monkeypatch):
"""Only datetime.today() is mocked and returns some date in 1900. datetime.now() returns still the current date."""
with monkeypatch.context() as mpc:
mpc.setattr(sys.modules[__name__], 'datetime', MockedDatetime)
assert datetime.today() == MOCKED_DATETIME_TODAY # datetime.today() mocked
assert datetime.now() > MOCKED_DATETIME_TODAY # datetime.now() not mocked
assert datetime.today() > MOCKED_DATETIME_TODAY # not mocked anymore

Categories