Time Travel, unittest.mock, freezegun and monkeypatch

To test time-dependant programs, such as timelapse camera, we can fudge the system time (sleep,. now()) in Python. Some options are:

An example using freezegun and monkeypatch

# chilly_bin_test.py
#
from freezegun import freeze_time
import time
import another_module

def test_capture(monkeypatch):  
    # fake time with freezegun
    with freeze_time(parse("2000-01-01 00:00:00")) as frozen_datetime:
        def sleepless(s):
            """ instead of really sleeping, just move frozen time forward """
            td = timedelta(seconds=s)
            frozen_datetime.tick(td)
        c1 = Camera()
        c1.config("./camera_app/tests/camera-test-config-1.toml")
        # replace real camera will a dummy using Mock. Could also use monkeypatch (?)
        c1._camera = unittest.mock.MagicMock(capture=True)
        # fake sleeping using monkeypatch
        monkeypatch.setattr(time, 'sleep', sleepless)
        # Now time.sleep() runs sleepless():
        time.sleep(10) #  locally ...
        c1.run(3)      # and works in another module 

# another_module.py
#
import time # careful will naming of time, datetime, etc because
            # there is also a datetime.datetime.sleep

class Camera():
    def run(n):
        time.sleep(10) # won't really sleep! use full name

An example of time changing using mock:

import unittest.mock
from datetime import datetime # for local use

# normally in another module
def thing_to_test():
    from datetime import datetime # load so can be patched !!!
    print("thing_to_test: {}".format(datetime.now()))
    print("thing_to_test: {}".format(datetime.now()))

ts = [datetime(2000, 1, 1, 1, 1, 1), datetime(2000, 1, 2, 1, 1, 1)]

@unittest.mock.patch('datetime.datetime')
def test2(self):
    self.now.side_effect = ts   
    thing_to_test()

test2()

One thought on “Time Travel, unittest.mock, freezegun and monkeypatch

  1. I’m running exactly into this scenario, except there’s a snag. I have multiple `Thread` objects that are each using `sleep` (or `asyncio.sleep` or `threading.Event.wait(…)`, but for sake of argument let’s limit to `time.sleep`). So I can’t simply advance time in one thread, as the other threads aren’t sleeping on the same schedule!

    As an example, we might have two polling loops for (stubbed) external time-varying data, and a third loop that collects both sources and decides, based on values and receipt times, which one to pass through as the source of truth.

    Is this test doing too much? Arguably. Each of the three components above could be tested in isolation. But one of our requirements are a few very high level tests that excretes the whole system in concert, given that the nature of the time-varying interactions is worth testing. So given the goal, what’s a tester to do?

    The best I’ve come up with is to override `sleep` to sleep for a fraction of the time, so that relative timings are still correct. But this still leaves a whole at direct time comparisons, so I’d need to use freezegun and somehow synchronize it to the sleeps that are occurring. At this point I’m a bit stumped. I’m currently running the tests in real time with very limited data streams — it’s not pretty, but it’s a lot better than the manual testing that came before!

    Any thoughts or suggestions for dealing with coordinating time travel across multiple actors?

Leave a Reply to Andrew Schwartz Cancel reply

Your email address will not be published.