2

I'm writing some asyncio-based code, and I'm trying to accomplish scheduled actions. I'd like to write some unit-tests for my code. What is the "good" way to unit-test code which involves call_later() actions? I would like to avoid actually waiting for several seconds, so I'd need to mock out the timing somehow.

Minimal example:

import asyncio

def do_more_stuff():
    print("doing more stuff")

async def do_stuff():
    print("doing stuff")
    await asyncio.sleep(0.1)
    print("scheduling more stuff")
    asyncio.get_event_loop().call_later(2, do_more_stuff)


def test_delayed_action(event_loop: asyncio.AbstractEventLoop):
    asyncio.set_event_loop(event_loop)

    asyncio.get_event_loop().create_task(do_stuff())
    event_loop.run_forever()

This example has multiple problems:

  • Because of the run_forever(), it doesn't terminate after do_more_stuff() was called. I'd like to have event_loop run until there are no more callbacks scheduled. Is this possible?

  • Even if I hack in a future and use event_loop.run_until_complete(fut), this test still takes 2 seconds to finish. I'd like to either only run do_stuff() and inspect the scheduled callbacks; or have the time advanced to speed up the triggering of the callbacks. Is either of these possible?

Niobos
  • 880
  • 4
  • 15
  • Is `do_more_stuff` part of the test? If so, you can add `event_loop.stop()` to it. As for your other question, I don't think it's possible to speed up the time. – user4815162342 Jul 26 '19 at 13:49
  • `do_more_stuff()` is part of the "production" code, not of the test code. But thanks for pointing me to `event_loop.stop()`, that may be useful to put in a mock somewhere. – Niobos Jul 27 '19 at 19:50
  • I guess you could monkeypatch `do_more_stuff` to call the original and then call `loop.stop()` or equivalent. – user4815162342 Jul 27 '19 at 20:42

0 Answers0