In this post, we looks into unit testing some calendar utilities in Python.
A requirement for unit testing those is to “mock” current date and time, i.e., overriding those returned by today
and now
methods with some specific date values (e.g., a date in future).
Calendar types
What is a big deal about calendar utitlities? There are surprisingly many types of calendar. Some of them are: regular calendar, lunar calendar, fiscal calendar, retail calendar. See here for more information of each calendar type. Out of the above calendar types, retail calendar seems to have more complex rules. However, this calendar type is frequently used in industries like retail and manufacturing for ease of planning around it.
Mocking current time in Python
Due to retail calendar’s desirable characteristics, we may have code that work with retail calendars in commercial applications eventually. I ended up working with a utility Python module for retail calendar with functions which return values based on current time/date. For example, a utility function to check if a given date is in the current 544 year works like this:
1 2 3 4 5 6 |
|
Some utility functions in that module are even more complicated than this example function.
For those, I think calling today
or now
inside those functions is a bad design.
They are essentially another variable in those functions (i.e., when do you run?), and it is better to expose that variable as an input parameter.
In addition, being able to specify what “today” or “now” value is will make automated unit testing easier.
For example, I want to know how my Python programs work if it runs on a particular date, such as end of retail year July 29, 2006.
A probably better, more testable function would be something like this.
1 2 3 4 5 |
|
However, in reality, you sometimes have to live with the original utility Python module.
Then, the workaround for unit testing is to “mock” current date and time, i.e., overriding those returned by today
and now
methods with some specific date values.
In Python, it can be done by using some mocking framework, such as illustrated here.
Fortunately, my life was made even easier with freezegun
library.
To install freezegun
on Mac OSX, simply run
1
|
|
Using this freezegun
library, I can easily specify my “current date” as “July 29, 2006” by adding the following decorator with some string “2006-07-29” for that date.
1 2 3 4 5 6 |
|
For full usage of freezegun
, refer to its quickstart guide.
It should be noted that freezegun
can mock datetime
calls from other modules and it works great for testing with datetime
calls.
However, you might encounter some occasional failures in your unit tests when working with time
module.
From my personal experience, in those cases, note that time zones must be accounted for when mocking with time
module by specifying tz_offset
in the decorator freeze_time
.