Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make unit test with `asyncio.sleep()` contained code?

Tags:

python

I have a problem to write asyncio.sleep contained unit tests. Do I wait actual sleep time...?

I used freezegun to mocking time. This library is really helpful when I try to run tests with normal callables. but I cannot find answer to run tests which contains asyncio.sleep!

async def too_many_sleep(delay):
    await asyncio.sleep(delay)
    do_something()

def test_code():
    task = event_loop.create_task(too_many_sleep(10000))
    # I want test like `assert_called(do_something)` without realtime delays

What I want:

def test_code():
    task = event_loop.create_task(too_many_sleep(10000))

    ...
    # trick the time
    with time_shift(sec=10000):
        assert task.done()

What I'm doing:

def test_code():
    task = event_loop.create_task(too_many_sleep(10000))
    # run tests and I will see a sunrise
like image 826
Lama Avatar asked Sep 01 '19 17:09

Lama


1 Answers

No, freezegun doesn't patch affect asyncio.sleep(), because freezegun doesn't patch the asyncio loop.time() method.

There is an existing issue in the freezegun project repository that asks how to deal with asyncio.sleep(), but it is still open with no proposed solution.

You could just mock asyncio.sleep() yourself:

from unittest import mock

class AsyncMock(mock.MagicMock):
    async def __call__(self, *args, **kwargs):
        return super(AsyncMock, self).__call__(*args, **kwargs)

with mock.patch('asyncio.sleep', new_callable=AsyncMock):
    task = event_loop.create_task(too_many_sleep(10000))

The above replaces asyncio.sleep with an AsyncMock() instance for the duration of the test, and AsyncMock(), when called, just does nothing.

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

Martijn Pieters