CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/pytest-asyncio-patterns

Configures and runs async Python tests with pytest-asyncio: installs the plugin, selects asyncio_mode (auto vs strict), scopes event loops (function/class/module/session), writes async fixtures with @pytest_asyncio.fixture, mocks coroutines with AsyncMock, and tests FastAPI (httpx.AsyncClient + ASGITransport) and aiohttp (aiohttp_client fixture) applications. Use when a Python project contains async def test_ functions, FastAPI/aiohttp endpoints, or any asyncio-based code that needs pytest integration. Do NOT use for general pytest fixture design, parametrize patterns, or conftest.py structure without an asyncio-specific problem (event-loop scoping, mode config, AsyncMock, ASGI client): use pytest-tests for those.

79

Quality

99%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

framework-clients.mdreferences/

Async framework client patterns

Deeper framework-specific async test patterns. The SKILL.md spine keeps the minimal FastAPI AsyncClient example; FastAPI lifespan events, aiohttp, and anyio live here.

FastAPI lifespan events (asgi-lifespan)

AsyncClient does not fire lifespan events by default (per fastapi.tiangolo.com/advanced/async-tests). To trigger startup/shutdown handlers, use asgi-lifespan:

pip install asgi-lifespan
from asgi_lifespan import LifespanManager

@pytest_asyncio.fixture(scope="module")
async def live_app():
    async with LifespanManager(app) as manager:
        yield manager.app

@pytest.mark.asyncio(loop_scope="module")
async def test_with_lifespan(live_app):
    async with AsyncClient(
        transport=ASGITransport(app=live_app),
        base_url="http://test",
    ) as client:
        response = await client.get("/health")
    assert response.status_code == 200

aiohttp apps (pytest-aiohttp)

Per docs.aiohttp.org/testing, the pytest-aiohttp plugin provides an aiohttp_client fixture that manages server startup and teardown:

pip install pytest-aiohttp
# pyproject.toml
[tool.pytest.ini_options]
asyncio_mode = "auto"
from aiohttp import web

async def hello(request):
    return web.Response(text="Hello, world")

async def test_hello(aiohttp_client):
    app = web.Application()
    app.router.add_get("/", hello)
    client = await aiohttp_client(app)
    resp = await client.get("/")
    assert resp.status == 200
    text = await resp.text()
    assert text == "Hello, world"

aiohttp_client returns a TestClient that starts the server on a random port and shuts it down after the test.

anyio as an alternative

Per anyio.readthedocs.io/testing, anyio ships its own pytest plugin that runs async tests on both asyncio and Trio backends. Use it when the codebase is written against anyio primitives or when multi-backend verification is needed.

pip install anyio[trio]
import pytest

@pytest.mark.anyio
async def test_anyio_style():
    result = await compute()
    assert result == 42

Parametrize backends:

# conftest.py
import pytest

@pytest.fixture(params=["asyncio", "trio"])
def anyio_backend(request):
    return request.param

anyio conflicts with pytest-asyncio auto mode; when both plugins are present, set only one to auto.

SKILL.md

tile.json