datetime
object# Code for this blog post:
git clone https://github.com/wgwz/patching-datetime-objects.git
# Checkout the code for section 1 and 2 respectively
git checkout 1a
git checkout 2a
# Running the code:
python3 lib.py
datetime
object be a problem?Python places some restrictions patching builtin's, and datetime
is a builtin.
I won't say that patching datetime
objects is incredibly important.
But it is definitely useful, for the sake of thorough unit testing.
i.e. If you hard-code a date or time in your tests, without patching, your
tests will fail when they get run on a different day.
This post will demonstrate the pitfall I ran into, and the way I currently
patch the datetime
object.
Presumably the pitfalls in patching other builtin objects are similar, and the
method here can be applied to those as well.
datetime.utcnow
fail?When you patch datetime.utcnow
directly.
@patch('__main__.datetime.utcnow')
def test_get_function(self, mock_utcnow):
mock_utcnow.return_value = 'pAtChEd'
assert get() == 'pAtChEd'
To me this seems like a pretty reasonable approach. But alas, we cannot patch builtins. When you run this code, we get the following error message:
TypeError: can't set attributes of built-in/extension type 'datetime.datetime'
Patch the datetime
object instead.
@patch('__main__.datetime')
def test_get_function(self, mock_dt):
mock_dt.utcnow.return_value = 'pAtChEd'
assert get() == 'pAtChEd'
The solution is mock the datetime
object in it's entirety.
Then specify that the mock datetime
object should return a given value, when
the method utcnow
is called:
mock_dt.utcnow.return_value = 'pAtChEd'
And there we have it. When you run into this type of error during mocking, patch at a higher-level!
Happy unit-testing! 🐐