I am trying to run an async test case in a loop, with Python’s unittesting framework; however, I am running into a brick wall with the error: AssertionError: asyncio runner is already initialized
As part of my loop, I have to reinitialise the test suite as following:
<code>tests = get_tests()
suite = unittest.TestSuite(tests)
runner = unittest.TextTestRunner()
result = runner.run(suite)
unittest.registerResult(result)
suite = unittest.TestSuite(tests)
<code>tests = get_tests()
suite = unittest.TestSuite(tests)
runner = unittest.TextTestRunner()
for _ in range(3):
result = runner.run(suite)
unittest.registerResult(result)
suite = unittest.TestSuite(tests)
</code>
tests = get_tests()
suite = unittest.TestSuite(tests)
runner = unittest.TextTestRunner()
for _ in range(3):
result = runner.run(suite)
unittest.registerResult(result)
suite = unittest.TestSuite(tests)
The test that is causing problems is (minimal version):
async def basic_async_func():
class MyAsyncTestClass(unittest.IsolatedAsyncioTestCase):
# Handling async class set up
asyncio.run(cls.asyncSetUpClass())
async def asyncSetUpClass(cls):
cls.statement = await basic_async_func()
self.assertEqual(self.statement,'hello')
<code>
async def basic_async_func():
await asyncio.sleep(2)
return 'hello'
class MyAsyncTestClass(unittest.IsolatedAsyncioTestCase):
@classmethod
def setUpClass(cls):
cls.name = 'foo'
# Handling async class set up
asyncio.run(cls.asyncSetUpClass())
@classmethod
async def asyncSetUpClass(cls):
cls.statement = await basic_async_func()
def test_set_up(self):
self.assertEqual(self.statement,'hello')
</code>
async def basic_async_func():
await asyncio.sleep(2)
return 'hello'
class MyAsyncTestClass(unittest.IsolatedAsyncioTestCase):
@classmethod
def setUpClass(cls):
cls.name = 'foo'
# Handling async class set up
asyncio.run(cls.asyncSetUpClass())
@classmethod
async def asyncSetUpClass(cls):
cls.statement = await basic_async_func()
def test_set_up(self):
self.assertEqual(self.statement,'hello')
I get the following output:
<code>Traceback (most recent call last):
File "/home/main.py", line 151, in <module>
File "/home/main.py", line 116, in main
test_result = runner.run(single_suite)
File "/usr/lib/python3.12/unittest/runner.py", line 240, in run
File "/usr/lib/python3.12/unittest/suite.py", line 84, in __call__
return self.run(*args, **kwds)
File "/usr/lib/python3.12/unittest/suite.py", line 122, in run
File "/usr/lib/python3.12/unittest/case.py", line 690, in __call__
return self.run(*args, **kwds)
File "/usr/lib/python3.12/unittest/async_case.py", line 129, in run
self._setupAsyncioRunner()
File "/usr/lib/python3.12/unittest/async_case.py", line 120, in _setupAsyncioRunner
assert self._asyncioRunner is None, 'asyncio runner is already initialized'
^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: asyncio runner is already initialized
<code>Traceback (most recent call last):
File "/home/main.py", line 151, in <module>
main()
File "/home/main.py", line 116, in main
test_result = runner.run(single_suite)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/unittest/runner.py", line 240, in run
test(result)
File "/usr/lib/python3.12/unittest/suite.py", line 84, in __call__
return self.run(*args, **kwds)
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/unittest/suite.py", line 122, in run
test(result)
File "/usr/lib/python3.12/unittest/case.py", line 690, in __call__
return self.run(*args, **kwds)
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/unittest/async_case.py", line 129, in run
self._setupAsyncioRunner()
File "/usr/lib/python3.12/unittest/async_case.py", line 120, in _setupAsyncioRunner
assert self._asyncioRunner is None, 'asyncio runner is already initialized'
^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: asyncio runner is already initialized
</code>
Traceback (most recent call last):
File "/home/main.py", line 151, in <module>
main()
File "/home/main.py", line 116, in main
test_result = runner.run(single_suite)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/unittest/runner.py", line 240, in run
test(result)
File "/usr/lib/python3.12/unittest/suite.py", line 84, in __call__
return self.run(*args, **kwds)
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/unittest/suite.py", line 122, in run
test(result)
File "/usr/lib/python3.12/unittest/case.py", line 690, in __call__
return self.run(*args, **kwds)
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/unittest/async_case.py", line 129, in run
self._setupAsyncioRunner()
File "/usr/lib/python3.12/unittest/async_case.py", line 120, in _setupAsyncioRunner
assert self._asyncioRunner is None, 'asyncio runner is already initialized'
^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: asyncio runner is already initialized
I have tried a few different things to resolve this.
Firstly, I’d originally manually set an event loop:
<code>cls.loop = asyncio.new_event_loop()
asyncio.set_event_loop(cls.loop)
cls.loop.run_until_complete(cls.asyncSetUpClass())
<code>cls.loop = asyncio.new_event_loop()
asyncio.set_event_loop(cls.loop)
cls.loop.run_until_complete(cls.asyncSetUpClass())
</code>
cls.loop = asyncio.new_event_loop()
asyncio.set_event_loop(cls.loop)
cls.loop.run_until_complete(cls.asyncSetUpClass())
Secondly, I tried using the asyncio.runner context manager:
<code>with asyncio.Runner() as runner:
runner.run(cls.asyncSetUpClass())
<code>with asyncio.Runner() as runner:
runner.run(cls.asyncSetUpClass())
</code>
with asyncio.Runner() as runner:
runner.run(cls.asyncSetUpClass())
Lastly, I tried to remove the classSetUp method (though this has been a requirement of my actual, non-minimal test case), and to instead just use IsolatedAsyncioTestCase’s asyncSetUp
function:
<code>async def asyncSetUp(self):
self.statement = await basic_async_func()
<code>async def asyncSetUp(self):
self.name = 'foo'
self.statement = await basic_async_func()
</code>
async def asyncSetUp(self):
self.name = 'foo'
self.statement = await basic_async_func()
All of these have given the same error output as above. I am wondering if I need to somehow set or close an asyncio runner at the level of the loop in the first code block? (I tried re-initialising the unittest runner in every loop iteration and this didn’t work)