Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock python's datetime.now() in a class method for unit testing?

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 datetime.datetime.now(timezone)      def do_many_things(self, tz_string='Europe/London'):         tz = pytz.timezone(tz_string)         localtime_now = self.get_now(tz)         ...         return things 

I want to test it, and to do so I need to make sure that the datetime.datetime.now() call returns something predictable.

I've been reading lots of examples of using Mock in tests, but haven't found anything quite like what I need, and I can't work out how to use it in my tests.

I separated the get_now() method out in case it's easier to mock that, instead of datetime.datetime.now(), but I'm still stumped. Any thoughts on how to write UnitTests for this using Mock? (This is all in Django, fwiw; I'm not sure if this makes a difference in this case.)

like image 886
Phil Gyford Avatar asked Oct 25 '12 16:10

Phil Gyford


2 Answers

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.

like image 154
Jocelyn delalande Avatar answered Sep 27 '22 20:09

Jocelyn delalande


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.

like image 20
Martijn Pieters Avatar answered Sep 27 '22 21:09

Martijn Pieters