I define aiohttp.Applcation
and unittest
for the Application
like the below.
# main.py
import asyncio
from aiohttp import web
async def background_task():
await asyncio.sleep(5)
async def start_up_test(app):
app.loop.create_task(background_task())
def get_application(bg_tasks=[]):
app = web.Application()
app.on_startup.append(start_up_test)
return app
# main_test.py
import main
from aiohttp import test_utils
class TestMain(test_utils.AioHTTPTestCase):
async def get_application(self):
return main.get_application()
@test_utils.unittest_run_loop
async def test_main(self):
pass
$ python -m unittest main_test
Task exception was never retrieved
future: <Task finished coro=<background_task() done, defined at /home/sangmin/workspace/main.py:78> exception=RuntimeError("There is no current event loop in thread 'MainThread'.",)>
Traceback (most recent call last):
File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
result = coro.send(None)
File "/home/sangmin/workspace/main.py", line 79, in background_task
await asyncio.sleep(5)
File "/usr/lib/python3.5/asyncio/tasks.py", line 510, in sleep
loop = events.get_event_loop()
File "/usr/lib/python3.5/asyncio/events.py", line 632, in get_event_loop
return get_event_loop_policy().get_event_loop()
File "/usr/lib/python3.5/asyncio/events.py", line 578, in get_event_loop
% threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'MainThread'.
.
----------------------------------------------------------------------
Ran 1 test in 0.021s
OK
The TestCase
raises an exception saying There is no current event loop in thread 'MainThread'
.
Then I found aiohttp
DOC mentioning about main loop
while unit-testing.
Some libraries like motor, aioes and others depend on the asyncio loop for executing the code. When running your normal program, these libraries pick the main event loop by doing asyncio.get_event_loop.
The problem during testing is that there is no main loop assigned because an independent loop for each test is created without assigning it as the main one.
According to the DOC, the cause of the exception is because asyncio.get_event_loop
is called while no main loop
is assigned on unittest
and I can see await asyncio.sleep(1)
access main loop
by calling get_event_loop
in above Trace
.
Then, I am so confused since I think Application
should be running over test loop
served by AioHTTPTestCase
and all of the coroutines in the Application
also should use the same loop
not main loop
.
What do I have missed and how do I fix it?
-----Edit-----
Tracing aiohttp
source code, I could make the issue simplify.
import asyncio
async def test():
await asyncio.sleep(1)
if __name__ == '__main__':
# setUp method of AioHTTPTestCase clear main loop and return new loop.
asyncio.set_event_loop(None)
loop = asyncio.new_event_loop()
# unittest_run_loop decorator run coroutine over the new loop.
loop.run_until_complete(test())
# This simple code also raises the same exception.
This behavior is normal for asyncio
.