How to Mock anyio.run Backends (asyncio vs trio) in Python
Demonstrates how to mock anyio.run to verify backend selection (asyncio or trio) without actually running the event loop.
pip install anyio
Python code
28 linesimport anyio
from unittest.mock import Mock, patch
async def fetch_data():
await anyio.sleep(0.1)
return {"data": 42}
def run_with_backend(backend: str):
async def main():
result = await fetch_data()
print(f"[{backend}] Result: {result}")
anyio.run(main, backend=backend)
if __name__ == "__main__":
# Demonstrate with mocked backends to show how anyio uses them
for backend in ["asyncio", "trio"]:
# Patch anyio.run to show which backend would be used
with patch("anyio.run") as mock_run:
mock_run.side_effect = lambda func, backend=backend, **kwargs: (
print(f"[{backend}] anyio.run called (simulated)")
)
# Recreate the call with our backend parameter
run_with_backend(backend)
print(f"Mock confirmed: backend='{backend}' selected")
Output
[asyncio] anyio.run called (simulated)
Mock confirmed: backend='asyncio' selected
[trio] anyio.run called (simulated)
Mock confirmed: backend='trio' selected
How it works
The patch context manager replaces anyio.run with a mock. The side_effect lambda prints a simulated call message, allowing you to observe which backend the code would use without executing the actual event loop. The backend parameter is captured via a default argument to ensure it's correct inside the mock. This technique is useful for testing functions that call anyio.run without tying tests to a specific backend.
Common mistakes
- Forgetting to pass `backend` as a keyword argument to `anyio.run` if your code expects positional.
- Not using `side_effect` correctly: the lambda must accept the same arguments as the mocked function.
- Mocking the wrong name (e.g., `anyio.run` vs `backend` functions) causing patch to have no effect.
Variations
- Use `mock_run.assert_called_once_with(backend='asyncio')` to assert backend selection.
- Test with real backends by running `anyio.run(main)` and checking `anyio.get_backend()` inside the coroutine.
Real-world use cases
- Unit testing code that switches backends for testing compatibility with asyncio and trio.
- Verifying that a library correctly selects a backend when multiple are available in a project.
- Writing CI checks to ensure your async code works on both supported backends without running full event loops.
Sponsored
More from Concurrency & performance
- Benchmark list.append vs deque.append in Python medium
- Build a Python Performance Profiler That Generates Readable Reports medium
- Graceful Shutdown Executor Context Manager in Python medium
- How to Build a Producer-Consumer Pattern with asyncio.Queue in Python medium
- How to Cancel an asyncio Task with Graceful Cleanup in Python medium
- How to Convert Data in Parallel with ThreadPoolExecutor in Python easy
Keep learning
Related tutorials and quizzes for this topic.