Testing Async Code (pytest-asyncio)
On this page
Async Tests Need Explicit Control
Async tests must await all work and enforce timeouts. Leaked tasks cause flaky builds and mysterious failures.
Async Test Pattern
import asyncio
async def work() -> str:
await asyncio.sleep(0.01)
return "ok"
def test_work():
out = asyncio.run(work())
assert out == "ok"
Timeout Guard
import asyncio
async def slow():
await asyncio.sleep(10)
def test_timeout():
with pytest.raises(asyncio.TimeoutError):
asyncio.run(asyncio.wait_for(slow(), timeout=0.05))
Operational Checklist
- Always await tasks or explicitly cancel them at test end.
- Use timeouts to prevent hung CI runs.
- Keep async tests deterministic (no real network unless integration).
Failure Modes
- Task leaks: background tasks continue into the next test.
- Hung builds: missing timeouts cause indefinite CI waits.