When I write with business logic, my code often depends on the current time. For example the algorithm which looks at each unfinished order and checks if an invoice should be sent (which depends on the no of days since the job was ended). In these cases creating an invoice is not triggered by an explicit user action but by a background job.
Now this creates a problem for me when it comes to testing:
So far I found two solutions:
The second approach was way more successful to me after all. Therefore I'm looking for a way to set the time Python's datetime+time modules return. Setting the date is usually enough, I don't need to set the current hour or second (even though this would be nice).
Is there such a utility? Is there an (internal) Python API that I can use?
For example, the %d-%m-%Y %H:%M:%S codes convert date to dd-mm-yyyy hh:mm:ss format. Use this step if you want to convert a time object to string format. like, hours minutes seconds ( hh:mm:ss ). Use the time.
The datetime. strptime() sets the hour and minute values to the default, 0 . Note that for a two-digit year (like 15 ) you'd use %y , not %Y , which is for a four-digit year. if you need to add an amount that is negative or more than one day then only the timedelta() solution would work.
Python Datetime module supplies classes to work with date and time. These classes provide a number of functions to deal with dates, times and time intervals. Date and datetime are an object in Python, so when you manipulate them, you are actually manipulating objects and not string or timestamps.
Monkey-patching time.time
is probably sufficient, actually, as it provides the basis for almost all the other time-based routines in Python. This appears to handle your use case pretty well, without resorting to more complex tricks, and it doesn't matter when you do it (aside from the few stdlib packages like Queue.py and threading.py that do from time import time
in which case you must patch before they get imported):
>>> import datetime >>> datetime.datetime.now() datetime.datetime(2010, 4, 17, 14, 5, 35, 642000) >>> import time >>> def mytime(): return 120000000.0 ... >>> time.time = mytime >>> datetime.datetime.now() datetime.datetime(1973, 10, 20, 17, 20)
That said, in years of mocking objects for various types of automated testing, I've needed this approach only very rarely, as most of the time it's my own application code that needs the mocking, and not the stdlib routines. After all, you know they work already. If you are encountering situations where your own code has to handle values returned by library routines, you may want to mock the library routines themselves, at least when checking how your own app will handle the timestamps.
The best approach by far is to build your own date/time service routine(s) which you use exclusively in your application code, and build into that the ability for tests to supply fake results as required. For example, I do a more complex equivalent of this sometimes:
# in file apptime.py (for example) import time as _time class MyTimeService(object): def __init__(self, get_time=None): self.get_time = get_time or _time.time def __call__(self): return self.get_time() time = MyTimeService()
Now in my app code I just do import apptime as time; time.time()
to get the current time value, whereas in test code I can first do apptime.time = MyTimeService(mock_time_func)
in my setUp()
code to supply fake time results.
Update: Years later there's an alternative, as noted in Dave Forgac's answer.
The freezegun package was made specifically for this purpose. It allows you to change the date for code under test. It can be used directly or via a decorator or context manager. One example:
from freezegun import freeze_time import datetime @freeze_time("2012-01-14") def test(): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
For more examples see the project: https://github.com/spulec/freezegun
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With