aiounittest
aiounittest is a helper library designed to simplify testing asynchronous Python code built with `asyncio`. It extends `unittest.TestCase` to support `async`/`await` syntax (Python 3.5+) and `asyncio.coroutine`/`yield from` (Python 3.4). The library is actively maintained, with its latest version being 1.5.0, released in March 2025.
Common errors
-
RuntimeError: got Future attached to a different loop
cause An `asyncio` object (like a `Future` or `Event`) was created using an event loop that is different from the one `aiounittest.AsyncTestCase` uses to run the actual test. This often happens when such objects are created in `setUp()`.fixEnsure that any `asyncio` objects required by your test are created within the `async def` test method itself, or use `self.loop` (if overridden `get_event_loop`) to explicitly get the test's event loop. -
RuntimeWarning: coroutine was never awaited
cause An `async def` function (coroutine) was called but its execution was not scheduled or awaited. `aiounittest.AsyncTestCase` automatically awaits `async def` test methods, but you must `await` any other coroutines called within your test.fixPrepend `await` to the call of any coroutine that you intend to execute, e.g., `await my_async_function()`. -
TypeError: object MagicMock is not awaitable
cause You are trying to `await` a standard `unittest.mock.MagicMock` object that is configured to mock an `async def` function. `MagicMock` by default is not awaitable.fixWhen mocking asynchronous functions, use `unittest.mock.AsyncMock` instead of `MagicMock`. For example: `with patch('module.async_func', new_callable=AsyncMock) as mock_func:` or use `aiounittest.futurized`.
Warnings
- deprecated For Python 3.8 and newer, consider using the built-in `unittest.IsolatedAsyncioTestCase`. The standard library's `unittest` now includes native support for asynchronous tests, reducing the need for `aiounittest` in many cases.
- gotcha Creating `asyncio` loop-dependent objects (like `asyncio.Event`) in `setUp()` methods of `aiounittest.AsyncTestCase` can lead to `RuntimeError: got Future attached to a different loop`. `AsyncTestCase` creates a fresh event loop for each test, *after* `setUp()` and *before* the test method runs.
- deprecated The `@asyncio.coroutine` decorator (for `yield from` syntax) was deprecated in Python 3.8. While `aiounittest` supports it for backward compatibility, it's recommended to use `async def` and `await` for new code.
Install
-
pip install aiounittest
Imports
- AsyncTestCase
from aiounittest.case import AsyncTestCase
from aiounittest import AsyncTestCase
- async_test
from aiounittest import async_test
- futurized
from aiounittest import futurized
Quickstart
import asyncio
import aiounittest
import unittest
async def async_add(x, y, delay=0.01):
await asyncio.sleep(delay)
return x + y
class MyAsyncTest(aiounittest.AsyncTestCase):
async def test_async_addition(self):
result = await async_add(10, 20)
self.assertEqual(result, 30)
def test_sync_method(self):
self.assertTrue(True)
# To run the tests (usually handled by test runners like `pytest` or `unittest` CLI)
if __name__ == '__main__':
unittest.main()