[{"data":1,"prerenderedAt":86},["ShallowReactive",2],{"qa-\u002Ffastapi\u002Ftesting\u002Fasync-testing":3},{"page":4,"siblings":76,"blog":68},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":12,"path":20,"questions":21,"questionsCount":67,"related":68,"seo":69,"seoDescription":70,"stem":71,"subtopic":6,"topic":72,"topicSlug":73,"updated":74,"__hash__":75},"qa\u002Ffastapi\u002Ftesting\u002Fasync-testing.md","Async Testing",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"hard","md","FastAPI","fastapi",{},true,"\u002Ffastapi\u002Ftesting\u002Fasync-testing",[22,27,31,35,39,43,47,51,55,59,63],{"id":23,"difficulty":24,"q":25,"a":26},"why-async-tests","medium","Why do you need special handling for async tests in FastAPI?","`TestClient` is synchronous — it works for most FastAPI tests. But some scenarios\nrequire true async tests:\n- Testing async dependencies directly (e.g., `get_async_db`).\n- Using async database fixtures (creating tables, seeding data).\n- Testing WebSocket connections with `AsyncClient`.\n- Testing code that uses `asyncio.gather` or `asyncio.create_task`.\n\nPlain `pytest` doesn't run `async def` test functions. You need a plugin:\n\n```bash\npip install anyio[trio] pytest-anyio   # recommended with FastAPI\u002FStarlette\n# OR\npip install pytest-asyncio\n```\n\nRule of thumb: use `TestClient` (sync) for HTTP endpoint tests — it's simpler;\nuse async tests only when you genuinely need to `await` inside the test body.\n",{"id":28,"difficulty":24,"q":29,"a":30},"pytest-anyio-setup","How do you configure `pytest-anyio` for FastAPI async tests?","Mark async tests with `@pytest.mark.anyio` or configure anyio as the default\nasync mode:\n\n```python\n# conftest.py — set anyio as default for the whole session\nimport pytest\n\n@pytest.fixture(scope=\"session\")\ndef anyio_backend():\n    return \"asyncio\"\n```\n\n```python\n# test_async.py\nimport pytest\n\n@pytest.mark.anyio\nasync def test_async_endpoint():\n    async with AsyncClient(transport=ASGITransport(app=app), base_url=\"http:\u002F\u002Ftest\") as client:\n        response = await client.get(\"\u002Fitems\")\n        assert response.status_code == 200\n```\n\nRule of thumb: set `anyio_backend = \"asyncio\"` globally in `conftest.py` to\navoid repeating the marker on every async test.\n",{"id":32,"difficulty":24,"q":33,"a":34},"async-client","How do you use `httpx.AsyncClient` to test a FastAPI app?","Use `ASGITransport` to route requests directly to the ASGI app without a network:\n\n```python\nimport pytest\nimport httpx\nfrom httpx import AsyncClient, ASGITransport\nfrom app.main import app\n\n@pytest.mark.anyio\nasync def test_get_item():\n    async with AsyncClient(\n        transport=ASGITransport(app=app),\n        base_url=\"http:\u002F\u002Ftestserver\",\n    ) as client:\n        response = await client.get(\"\u002Fitems\u002F1\")\n        assert response.status_code == 200\n        assert response.json()[\"id\"] == 1\n```\n\n`ASGITransport` calls the app's ASGI interface directly — no TCP socket needed.\n\nRule of thumb: use `AsyncClient` for async tests; use `TestClient` for sync\ntests — `AsyncClient` requires `async with` and an event loop.\n",{"id":36,"difficulty":24,"q":37,"a":38},"async-client-auth","How do you add auth headers to an `httpx.AsyncClient` for multiple test requests?","Set `headers=` in the `AsyncClient` constructor or use an `httpx.Auth` class:\n\n```python\n@pytest.mark.anyio\nasync def test_authenticated():\n    token = create_test_token(user_id=1)\n    async with AsyncClient(\n        transport=ASGITransport(app=app),\n        base_url=\"http:\u002F\u002Ftestserver\",\n        headers={\"Authorization\": f\"Bearer {token}\"},\n    ) as client:\n        resp = await client.get(\"\u002Fme\")\n        assert resp.status_code == 200\n        resp2 = await client.get(\"\u002Forders\")\n        assert resp2.status_code == 200\n```\n\nRule of thumb: set auth headers in the constructor for tests that make multiple\nauthenticated requests; pass `headers=` per-request when mixing auth states.\n",{"id":40,"difficulty":14,"q":41,"a":42},"async-db-fixture","How do you create an async database fixture for FastAPI integration tests?","```python\n# conftest.py\nimport pytest\nfrom sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession\nfrom app.db.base import Base\nfrom app.main import app\nfrom app.db.session import get_async_db\n\nTEST_DB = \"sqlite+aiosqlite:\u002F\u002F\u002F:memory:\"\n\n@pytest.fixture(scope=\"session\")\ndef anyio_backend():\n    return \"asyncio\"\n\n@pytest.fixture(scope=\"session\")\nasync def db_engine():\n    engine = create_async_engine(TEST_DB)\n    async with engine.begin() as conn:\n        await conn.run_sync(Base.metadata.create_all)\n    yield engine\n    await engine.dispose()\n\n@pytest.fixture\nasync def db_session(db_engine):\n    factory = async_sessionmaker(db_engine, expire_on_commit=False)\n    async with factory() as session:\n        yield session\n        await session.rollback()   # undo test writes\n\n@pytest.fixture\nasync def async_client(db_session):\n    async def override_db():\n        yield db_session\n    app.dependency_overrides[get_async_db] = override_db\n    async with AsyncClient(transport=ASGITransport(app=app), base_url=\"http:\u002F\u002Ftest\") as c:\n        yield c\n    app.dependency_overrides.clear()\n```\n\nRule of thumb: roll back after each test (`await session.rollback()`) rather\nthan truncating tables — rollback is faster and avoids FK constraint issues.\n",{"id":44,"difficulty":14,"q":45,"a":46},"websocket-testing","How do you test WebSocket endpoints in FastAPI?","Use `TestClient` with the `websocket_connect()` context manager:\n\n```python\nfrom fastapi.testclient import TestClient\n\ndef test_websocket_echo():\n    with TestClient(app) as client:\n        with client.websocket_connect(\"\u002Fws\") as ws:\n            ws.send_text(\"Hello\")\n            data = ws.receive_text()\n            assert data == \"Echo: Hello\"\n```\n\nFor async WebSocket tests with `httpx`:\n```python\n@pytest.mark.anyio\nasync def test_ws_async():\n    async with AsyncClient(transport=ASGITransport(app=app), base_url=\"http:\u002F\u002Ftest\") as client:\n        async with client.websocket_connect(\"\u002Fws\") as ws:\n            await ws.send_text(\"ping\")\n            msg = await ws.receive_text()\n            assert msg == \"pong\"\n```\n\nRule of thumb: use `TestClient.websocket_connect` for simple sync WS tests;\nuse async `AsyncClient` when the WS handler is complex and needs concurrent I\u002FO.\n",{"id":48,"difficulty":14,"q":49,"a":50},"event-loop-scope","What is event loop scope in pytest-asyncio\u002Fanyio and why does it matter?","Each pytest scope (`function`, `module`, `session`) can have its own event loop.\nBy default, each async test gets a **fresh event loop** (`scope=\"function\"`).\n\nThis matters because:\n- `scope=\"session\"` async fixtures (like a DB engine) must share an event loop\n  with the tests that use them.\n- Mixing scopes can cause \"Event loop is closed\" or \"attached to different loop\" errors.\n\nWith `pytest-anyio`, configure the scope:\n```python\n# conftest.py\n@pytest.fixture(scope=\"session\")\ndef anyio_backend():\n    return \"asyncio\"\n```\n\nThis uses a session-scoped event loop — all async fixtures and tests share one loop.\n\nRule of thumb: set `scope=\"session\"` for `anyio_backend` when you have\nsession-scoped async fixtures (DB engines, HTTP clients) — otherwise they can't\nbe awaited from function-scoped tests.\n",{"id":52,"difficulty":14,"q":53,"a":54},"trio-backend","Can FastAPI tests run on Trio instead of asyncio?","Yes — FastAPI is built on Starlette which uses `anyio`, supporting both asyncio\nand Trio. Change the backend in conftest:\n\n```python\n@pytest.fixture(scope=\"session\")\ndef anyio_backend():\n    return \"trio\"   # or \"asyncio\"\n```\n\nAnd mark tests:\n```python\n@pytest.mark.anyio\nasync def test_endpoint():\n    async with AsyncClient(...) as client:\n        ...\n```\n\nRunning on Trio can catch asyncio-specific bugs (e.g., code that relies on\nasyncio internals rather than anyio primitives).\n\nRule of thumb: run your test suite on both asyncio and Trio once in CI to catch\nportability issues; ship on asyncio for production (most libraries are asyncio-native).\n",{"id":56,"difficulty":24,"q":57,"a":58},"mock-async-service","How do you mock an async function dependency in a FastAPI test?","Use `unittest.mock.AsyncMock` or override the dependency:\n\n```python\nfrom unittest.mock import AsyncMock, patch\n\n# Option A — patch the async function directly\n@pytest.mark.anyio\nasync def test_with_mock():\n    with patch(\"app.services.email.send_email\", new_callable=AsyncMock) as mock_email:\n        async with AsyncClient(transport=ASGITransport(app=app), base_url=\"http:\u002F\u002Ftest\") as c:\n            resp = await c.post(\"\u002Fsignup\", json={\"email\": \"a@b.com\"})\n        assert resp.status_code == 201\n        mock_email.assert_called_once_with(\"a@b.com\", \"Welcome!\")\n\n# Option B — dependency override\nasync def fake_send_email(*args, **kwargs):\n    pass   # no-op\n\napp.dependency_overrides[send_email_dep] = lambda: fake_send_email\n```\n\nRule of thumb: use `dependency_overrides` for FastAPI-injected async deps;\nuse `AsyncMock` + `patch` for module-level async functions not in the DI graph.\n",{"id":60,"difficulty":14,"q":61,"a":62},"testing-background-tasks","How do you test that a BackgroundTask was scheduled and optionally verify it ran?","**Verify it was scheduled** — check the response immediately, background not run yet:\n```python\ndef test_signup_queues_email(client):\n    resp = client.post(\"\u002Fsignup\", json={\"email\": \"a@b.com\"})\n    assert resp.status_code == 201\n    # email runs after response — we can't assert it ran synchronously\n```\n\n**Verify it ran** — `TestClient` runs background tasks before closing:\n```python\nemails_sent = []\n\ndef fake_send_email(to: str, msg: str):\n    emails_sent.append(to)\n\napp.dependency_overrides[get_email_sender] = lambda: fake_send_email\n\ndef test_email_sent(client):\n    with TestClient(app) as c:    # lifespan + BG tasks run\n        c.post(\"\u002Fsignup\", json={\"email\": \"a@b.com\"})\n    assert \"a@b.com\" in emails_sent\n```\n\nRule of thumb: `TestClient` (sync) runs background tasks before `__exit__` —\nuse it to verify task execution; for async tests you may need to `await` explicitly.\n",{"id":64,"difficulty":24,"q":65,"a":66},"snapshot-testing","How do you test the exact JSON shape of a FastAPI response (snapshot testing)?","Use `syrupy` (snapshot testing library) or assert field-by-field:\n\n```python\n# Field-by-field (explicit)\ndef test_item_response(client):\n    resp = client.get(\"\u002Fitems\u002F1\")\n    data = resp.json()\n    assert data.keys() == {\"id\", \"name\", \"price\", \"created_at\"}\n    assert isinstance(data[\"id\"], int)\n    assert isinstance(data[\"price\"], float)\n\n# Snapshot (syrupy)\ndef test_item_snapshot(client, snapshot):\n    resp = client.get(\"\u002Fitems\u002F1\")\n    assert resp.json() == snapshot   # first run saves; subsequent runs compare\n```\n\nRule of thumb: explicit field assertions are more maintainable than full JSON\nsnapshots for frequently changing response shapes — snapshots are great for\nstable, complex nested responses.\n",11,null,{"description":11},"FastAPI async testing interview questions — pytest-anyio, httpx AsyncClient, async fixtures, event loop scope and testing async dependencies.","fastapi\u002Ftesting\u002Fasync-testing","Testing","testing","2026-06-20","Nyo-aoIOW4IEDEjf65eVCrhZM1CkcWl5y76T2eotItY",[77,81,82],{"subtopic":78,"path":79,"order":80},"TestClient","\u002Ffastapi\u002Ftesting\u002Ftest-client",1,{"subtopic":6,"path":20,"order":12},{"subtopic":83,"path":84,"order":85},"Dependency Overrides","\u002Ffastapi\u002Ftesting\u002Fdependency-overrides",3,1782244113518]