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.

Medium Python 3.9+ Aug 9, 2026 Concurrency & performance 14 views 0 copies

Requires third-party packages — install first
pip install anyio

Python code

28 lines
Python 3.9+
import 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

stdout
[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

  1. Use `mock_run.assert_called_once_with(backend='asyncio')` to assert backend selection.
  2. 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

Run locally

This sample needs third-party packages, so it cannot run in the browser IDE. Copy the code above, install the packages shown at the top, then run it in your own Python environment.

More from Concurrency & performance

Related tutorials and quizzes for this topic.