我为aiohttp.Applcation
定义了unittest
和Application
,如下所示。
# 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
TestCase
引发了一个例外There is no current event loop in thread 'MainThread'
。
然后我发现aiohttp
DOC在单元测试时提及main loop
。
某些库如motor,aioes和其他库依赖于asyncio循环来执行代码。运行正常程序时,这些库通过执行asyncio.get_event_loop来选择主事件循环。
测试期间的问题是没有分配主循环,因为创建了每个测试的独立循环而没有将其指定为主循环。
根据DOC,异常的原因是因为在asyncio.get_event_loop
上没有分配main loop
时调用unittest
,我可以看到await asyncio.sleep(1)
访问{{1通过调用main loop
上面的get_event_loop
。
然后,我很困惑,因为我认为Trace
应该由Application
服务的test loop
运行,并且AioHTTPTestCase
中的所有协同程序也应该使用相同的Application
loop
不是main loop
。
我错过了什么以及如何解决?
- - - - 修改 -----
跟踪aiohttp
源代码,我可以简化问题。
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.
这种行为对asyncio
来说是正常的。