[{"data":1,"prerenderedAt":217},["ShallowReactive",2],{"topic-fastapi-testing":3},{"framework":4,"topic":15,"subtopics":24},{"id":5,"description":6,"extension":7,"icon":8,"meta":9,"name":10,"order":11,"slug":8,"stem":12,"tier":13,"__hash__":14},"frameworks\u002Fframeworks\u002Ffastapi.yml","FastAPI interview questions on async routing, Pydantic validation, dependency injection, OAuth2 security, database integration and deployment — the go-to Python framework for production APIs.","yml","fastapi",{},"FastAPI",6,"frameworks\u002Ffastapi",1,"lgr_X74wBdBYovbrlazGWPWqqi-YwNEUq44l1BmtgyE",{"id":16,"description":17,"extension":7,"frameworkSlug":8,"meta":18,"name":19,"order":20,"slug":21,"stem":22,"__hash__":23},"topics\u002Ftopics\u002Ffastapi-testing.yml","TestClient, AsyncClient, pytest-asyncio and dependency overrides — the testing patterns FastAPI teams reach for in production codebases.",{},"Testing",7,"testing","topics\u002Ffastapi-testing","aoBJ66lxAhs9p_bkdduY2b_KOcOC_OUW2WJCgKvsSA4",[25,98,158],{"id":26,"title":27,"body":28,"description":32,"difficulty":35,"extension":36,"framework":10,"frameworkSlug":8,"meta":37,"navigation":38,"order":13,"path":39,"questions":40,"questionsCount":90,"related":91,"seo":92,"seoDescription":93,"stem":94,"subtopic":95,"topic":19,"topicSlug":21,"updated":96,"__hash__":97},"qa\u002Ffastapi\u002Ftesting\u002Ftest-client.md","Test Client",{"type":29,"value":30,"toc":31},"minimark",[],{"title":32,"searchDepth":33,"depth":33,"links":34},"",2,[],"medium","md",{},true,"\u002Ffastapi\u002Ftesting\u002Ftest-client",[41,46,50,54,58,62,66,70,74,78,82,86],{"id":42,"difficulty":43,"q":44,"a":45},"testclient-basics","easy","What is `TestClient` in FastAPI and how do you use it?","`TestClient` (from `starlette.testclient`) wraps your FastAPI app in a\n`requests`-compatible interface. It runs the full ASGI stack synchronously\nso you can test endpoints without starting a real server.\n\n```python\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n@app.get(\"\u002Fitems\u002F{id}\")\nasync def get_item(id: int):\n    return {\"id\": id}\n\nclient = TestClient(app)\n\ndef test_get_item():\n    response = client.get(\"\u002Fitems\u002F42\")\n    assert response.status_code == 200\n    assert response.json() == {\"id\": 42}\n```\n\nRule of thumb: create `TestClient` once per module (or as a pytest fixture)\nrather than on every test — instantiation is cheap but consistent fixture\nscope is cleaner.\n",{"id":47,"difficulty":35,"q":48,"a":49},"testclient-lifespan","How do you ensure lifespan events (startup\u002Fshutdown) run in tests?","Use `TestClient` as a **context manager**:\n\n```python\nfrom fastapi.testclient import TestClient\nfrom app.main import app\n\ndef test_with_lifespan():\n    with TestClient(app) as client:\n        # startup has run (DB connected, app.state populated)\n        response = client.get(\"\u002Fhealth\")\n        assert response.status_code == 200\n    # shutdown has run (DB disconnected)\n```\n\nWithout the `with` block, lifespan events don't run, and any code that depends\non `app.state` will fail.\n\nRule of thumb: always use `with TestClient(app) as client:` in tests that need\nstartup resources; plain `TestClient(app)` is fine for stateless routes.\n",{"id":51,"difficulty":43,"q":52,"a":53},"pytest-fixture-client","How do you set up a pytest fixture for a FastAPI `TestClient`?","```python\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom app.main import app\n\n@pytest.fixture(scope=\"module\")\ndef client():\n    with TestClient(app) as c:\n        yield c\n\ndef test_list_items(client):\n    resp = client.get(\"\u002Fitems\")\n    assert resp.status_code == 200\n\ndef test_create_item(client):\n    resp = client.post(\"\u002Fitems\", json={\"name\": \"Widget\", \"price\": 9.99})\n    assert resp.status_code == 201\n```\n\n`scope=\"module\"` starts the app once per module, which is faster than per-test.\nUse `scope=\"function\"` if tests mutate state that must be reset.\n\nRule of thumb: use `scope=\"module\"` for read-heavy test files; use `scope=\"function\"`\nfor tests that write to a database or modify `app.state`.\n",{"id":55,"difficulty":43,"q":56,"a":57},"json-body-test","How do you send a JSON body in a TestClient POST request?","Pass the `json=` keyword argument — TestClient serialises it and sets\n`Content-Type: application\u002Fjson` automatically:\n\n```python\ndef test_create_item(client):\n    response = client.post(\n        \"\u002Fitems\",\n        json={\"name\": \"Widget\", \"price\": 9.99},\n    )\n    assert response.status_code == 201\n    data = response.json()\n    assert data[\"name\"] == \"Widget\"\n    assert \"id\" in data\n```\n\nFor raw string bodies: `data='{\"name\":\"Widget\"}'` with `headers={\"Content-Type\": \"application\u002Fjson\"}`.\n\nRule of thumb: always use `json=` (not `data=`) for JSON payloads — it handles\nserialisation correctly and sets the content type header.\n",{"id":59,"difficulty":43,"q":60,"a":61},"headers-test","How do you send custom headers (e.g., Authorization) in TestClient?","Pass `headers=` dict to the request method:\n\n```python\ndef test_authenticated(client):\n    token = create_test_token(user_id=1)\n    response = client.get(\n        \"\u002Fme\",\n        headers={\"Authorization\": f\"Bearer {token}\"},\n    )\n    assert response.status_code == 200\n```\n\nOr set default headers on the client itself:\n```python\n@pytest.fixture\ndef auth_client(client):\n    token = create_test_token(user_id=1)\n    client.headers.update({\"Authorization\": f\"Bearer {token}\"})\n    return client\n```\n\nRule of thumb: create a separate `auth_client` fixture for tests that always\nneed auth headers — it avoids repeating the header on every request.\n",{"id":63,"difficulty":43,"q":64,"a":65},"query-params-test","How do you test query parameters with TestClient?","Pass `params=` dict:\n\n```python\ndef test_search(client):\n    response = client.get(\"\u002Fitems\", params={\"q\": \"widget\", \"page\": 2, \"size\": 10})\n    assert response.status_code == 200\n    # equivalent to GET \u002Fitems?q=widget&page=2&size=10\n```\n\nFor multi-value query params:\n```python\nresponse = client.get(\"\u002Fitems\", params=[(\"tags\", \"python\"), (\"tags\", \"web\")])\n# GET \u002Fitems?tags=python&tags=web\n```\n\nRule of thumb: use `params=` dict for simple query strings; use a list of tuples\nwhen the same key appears multiple times.\n",{"id":67,"difficulty":35,"q":68,"a":69},"cookies-test","How do you send cookies and test cookie-based auth with TestClient?","Set cookies on the client or per-request:\n\n```python\n# Per-request\ndef test_cookie_auth(client):\n    response = client.get(\"\u002Fprofile\", cookies={\"session\": \"valid-session-token\"})\n    assert response.status_code == 200\n\n# Persistent across requests (simulates browser session)\nclient.cookies.set(\"session\", \"valid-session-token\")\nresponse = client.get(\"\u002Fprofile\")\n```\n\nTestClient automatically carries `Set-Cookie` headers between requests\nwhen used as a context manager — simulating a browser:\n\n```python\nwith TestClient(app) as client:\n    client.post(\"\u002Flogin\", data={\"username\": \"alice\", \"password\": \"secret\"})\n    # client now has the session cookie\n    response = client.get(\"\u002Fprofile\")\n    assert response.status_code == 200\n```\n\nRule of thumb: use the `with TestClient(app)` context manager for tests that\nsimulate a full login → use → logout flow.\n",{"id":71,"difficulty":43,"q":72,"a":73},"form-data-test","How do you test form data submission with TestClient?","Pass `data=` (not `json=`) for URL-encoded form data:\n\n```python\ndef test_login_form(client):\n    response = client.post(\n        \"\u002Ftoken\",\n        data={\"username\": \"alice\", \"password\": \"secret\", \"grant_type\": \"password\"},\n    )\n    assert response.status_code == 200\n    assert \"access_token\" in response.json()\n```\n\nFor multipart file upload:\n```python\ndef test_file_upload(client):\n    response = client.post(\n        \"\u002Fupload\",\n        files={\"file\": (\"report.csv\", b\"id,name\\n1,Alice\", \"text\u002Fcsv\")},\n    )\n    assert response.status_code == 200\n```\n\nRule of thumb: use `data=` for form fields, `files=` for file uploads; never\nmix `json=` with `data=` in the same request.\n",{"id":75,"difficulty":35,"q":76,"a":77},"assert-validation-error","How do you test that FastAPI returns 422 for invalid input?","Send an intentionally malformed request and assert on the 422 status code and\nerror detail structure:\n\n```python\ndef test_invalid_price(client):\n    response = client.post(\"\u002Fitems\", json={\"name\": \"Widget\", \"price\": \"not-a-number\"})\n    assert response.status_code == 422\n    errors = response.json()[\"detail\"]\n    assert any(e[\"loc\"] == [\"body\", \"price\"] for e in errors)\n    assert any(e[\"type\"] == \"float_parsing\" for e in errors)\n```\n\nCheck `loc` (where the error is) and `type` (what kind of error) rather than\nthe `msg` string — messages can change between Pydantic versions.\n\nRule of thumb: assert on `detail[*].loc` and `detail[*].type` for validation\nerrors — these are stable; `msg` wording changes between library versions.\n",{"id":79,"difficulty":35,"q":80,"a":81},"raise-on-server-error","What is `raise_server_exceptions` and when should you disable it?","`TestClient` re-raises server-side exceptions by default (`raise_server_exceptions=True`).\nThis turns a 500 response into a Python exception in the test — useful for\ndebugging but unhelpful when you're testing error handling.\n\n```python\n# Test that a 500 is returned without raising\nclient = TestClient(app, raise_server_exceptions=False)\n\ndef test_internal_error():\n    response = client.get(\"\u002Fbroken\")\n    assert response.status_code == 500\n```\n\nOr use a context manager:\n```python\nwith TestClient(app, raise_server_exceptions=False) as client:\n    resp = client.get(\"\u002Fbroken\")\n    assert resp.status_code == 500\n```\n\nRule of thumb: keep the default (`True`) for development tests so unhandled\nexceptions surface immediately; set `False` when specifically testing error-handling middleware.\n",{"id":83,"difficulty":43,"q":84,"a":85},"test-redirect-follow","Does TestClient follow redirects by default and how do you control this?","`TestClient` follows redirects by default (`follow_redirects=True`). To test\nthat a redirect is issued without following it:\n\n```python\ndef test_redirect(client):\n    response = client.get(\"\u002Fold-path\", follow_redirects=False)\n    assert response.status_code == 301\n    assert response.headers[\"location\"] == \"\u002Fnew-path\"\n```\n\nTo disable redirect following globally:\n```python\nclient = TestClient(app, follow_redirects=False)\n```\n\nRule of thumb: disable `follow_redirects` when testing the redirect itself\n(status code + Location header); keep it enabled when you care about the\nfinal destination response.\n",{"id":87,"difficulty":35,"q":88,"a":89},"dependency-override-test","How do you replace a database dependency with an in-memory fake in tests?","Use `app.dependency_overrides`:\n\n```python\nfrom app.main import app\nfrom app.db import get_db\n\ndef fake_get_db():\n    db = FakeDatabase()\n    db.users = [{\"id\": 1, \"name\": \"Alice\"}]\n    yield db\n\napp.dependency_overrides[get_db] = fake_get_db\n\nclient = TestClient(app)\n\ndef test_list_users():\n    resp = client.get(\"\u002Fusers\")\n    assert resp.status_code == 200\n    assert len(resp.json()) == 1\n```\n\nAlways clean up after the test:\n```python\n@pytest.fixture(autouse=True)\ndef reset_overrides():\n    yield\n    app.dependency_overrides.clear()\n```\n\nRule of thumb: put `app.dependency_overrides.clear()` in an `autouse` fixture\nteardown — stale overrides in one test silently corrupt subsequent tests.\n",12,null,{"description":32},"FastAPI TestClient interview questions — requests-style testing, fixtures, status codes, headers, cookies and testing error responses.","fastapi\u002Ftesting\u002Ftest-client","TestClient","2026-06-20","IleoACMiE0Rdhnr9eoEdzZ9DlwJxNrNr7NnNqdzKO-s",{"id":99,"title":100,"body":101,"description":32,"difficulty":105,"extension":36,"framework":10,"frameworkSlug":8,"meta":106,"navigation":38,"order":33,"path":107,"questions":108,"questionsCount":153,"related":91,"seo":154,"seoDescription":155,"stem":156,"subtopic":100,"topic":19,"topicSlug":21,"updated":96,"__hash__":157},"qa\u002Ffastapi\u002Ftesting\u002Fasync-testing.md","Async Testing",{"type":29,"value":102,"toc":103},[],{"title":32,"searchDepth":33,"depth":33,"links":104},[],"hard",{},"\u002Ffastapi\u002Ftesting\u002Fasync-testing",[109,113,117,121,125,129,133,137,141,145,149],{"id":110,"difficulty":35,"q":111,"a":112},"why-async-tests","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":114,"difficulty":35,"q":115,"a":116},"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":118,"difficulty":35,"q":119,"a":120},"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":122,"difficulty":35,"q":123,"a":124},"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":126,"difficulty":105,"q":127,"a":128},"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":130,"difficulty":105,"q":131,"a":132},"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":134,"difficulty":105,"q":135,"a":136},"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":138,"difficulty":105,"q":139,"a":140},"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":142,"difficulty":35,"q":143,"a":144},"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":146,"difficulty":105,"q":147,"a":148},"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":150,"difficulty":35,"q":151,"a":152},"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,{"description":32},"FastAPI async testing interview questions — pytest-anyio, httpx AsyncClient, async fixtures, event loop scope and testing async dependencies.","fastapi\u002Ftesting\u002Fasync-testing","Nyo-aoIOW4IEDEjf65eVCrhZM1CkcWl5y76T2eotItY",{"id":159,"title":160,"body":161,"description":32,"difficulty":35,"extension":36,"framework":10,"frameworkSlug":8,"meta":165,"navigation":38,"order":166,"path":167,"questions":168,"questionsCount":153,"related":91,"seo":213,"seoDescription":214,"stem":215,"subtopic":160,"topic":19,"topicSlug":21,"updated":96,"__hash__":216},"qa\u002Ffastapi\u002Ftesting\u002Fdependency-overrides.md","Dependency Overrides",{"type":29,"value":162,"toc":163},[],{"title":32,"searchDepth":33,"depth":33,"links":164},[],{},3,"\u002Ffastapi\u002Ftesting\u002Fdependency-overrides",[169,173,177,181,185,189,193,197,201,205,209],{"id":170,"difficulty":43,"q":171,"a":172},"dependency-overrides-basics","What is `app.dependency_overrides` and how do you use it in tests?","`app.dependency_overrides` is a dict on the `FastAPI` instance. Map an original\ndependency function to a replacement callable — FastAPI calls the replacement\ninstead during test requests.\n\n```python\nfrom app.main import app\nfrom app.auth import get_current_user\nfrom fastapi.testclient import TestClient\n\ndef mock_user():\n    return {\"id\": 1, \"name\": \"Alice\", \"role\": \"admin\"}\n\napp.dependency_overrides[get_current_user] = mock_user\n\nclient = TestClient(app)\n\ndef test_protected_endpoint():\n    resp = client.get(\"\u002Fadmin\u002Fstats\")\n    assert resp.status_code == 200\n```\n\nRule of thumb: use `dependency_overrides` to replace any injected function —\nDB sessions, auth, settings, external API clients — without touching app code.\n",{"id":174,"difficulty":35,"q":175,"a":176},"cleanup-overrides","How do you ensure dependency overrides don't leak between tests?","Use a pytest `autouse` fixture to clear overrides after every test:\n\n```python\nimport pytest\nfrom app.main import app\n\n@pytest.fixture(autouse=True)\ndef reset_dependency_overrides():\n    yield\n    app.dependency_overrides.clear()\n```\n\nOr clear per-override:\n```python\n@pytest.fixture\ndef with_mock_user():\n    app.dependency_overrides[get_current_user] = lambda: {\"id\": 1}\n    yield\n    del app.dependency_overrides[get_current_user]\n```\n\nRule of thumb: always clean up overrides in fixture teardown — a leaked override\nin one test silently causes wrong behaviour in subsequent tests.\n",{"id":178,"difficulty":43,"q":179,"a":180},"override-return-value","Does the override function need the same signature as the original dependency?","No — the override only needs to return a compatible value. FastAPI replaces the\nentire callable, so the override's parameters are independently resolved by DI.\n\n```python\n# Original dep — reads from DB\nasync def get_current_user(token: str = Depends(oauth2_scheme)):\n    payload = decode_jwt(token)\n    return await db.get_user(payload[\"sub\"])\n\n# Override — returns a hardcoded user, no token needed\ndef mock_admin_user():\n    return User(id=1, name=\"Admin\", role=\"admin\")\n\napp.dependency_overrides[get_current_user] = mock_admin_user\n```\n\nThe override receives its own deps from DI — if it has parameters, they'll be\ninjected. If it has none, it just returns the hardcoded value.\n\nRule of thumb: keep override functions as simple as possible — bare lambdas or\nzero-argument functions returning fake objects are ideal for tests.\n",{"id":182,"difficulty":35,"q":183,"a":184},"override-with-settings","How do you override `BaseSettings` in tests using dependency overrides?","Override the `get_settings` dependency (the `@lru_cache` wrapper):\n\n```python\nfrom app.config import get_settings, Settings\nfrom app.main import app\n\ndef test_settings():\n    test_settings = Settings(\n        database_url=\"sqlite+aiosqlite:\u002F\u002F\u002F:memory:\",\n        secret_key=\"test-only-secret\",\n        debug=True,\n    )\n    app.dependency_overrides[get_settings] = lambda: test_settings\n\n    with TestClient(app) as client:\n        resp = client.get(\"\u002Fconfig\")\n        assert resp.json()[\"debug\"] is True\n\n    app.dependency_overrides.clear()\n```\n\nAlso clear the `@lru_cache` to prevent stale settings:\n```python\nget_settings.cache_clear()\n```\n\nRule of thumb: always pair `dependency_overrides[get_settings]` with\n`get_settings.cache_clear()` to prevent the cached production settings from\nbeing used despite the override.\n",{"id":186,"difficulty":35,"q":187,"a":188},"override-db-session","Show the standard pattern for replacing the DB session dependency in tests.","```python\n# conftest.py\nimport pytest\nfrom sqlalchemy import create_engine\nfrom sqlalchemy.orm import sessionmaker, Session\nfrom fastapi.testclient import TestClient\nfrom app.main import app\nfrom app.db.session import get_db\nfrom app.db.base import Base\n\nTEST_ENGINE = create_engine(\"sqlite:\u002F\u002F\u002F:memory:\", connect_args={\"check_same_thread\": False})\nTestingSessionLocal = sessionmaker(bind=TEST_ENGINE)\n\n@pytest.fixture(scope=\"module\", autouse=True)\ndef create_tables():\n    Base.metadata.create_all(bind=TEST_ENGINE)\n    yield\n    Base.metadata.drop_all(bind=TEST_ENGINE)\n\n@pytest.fixture\ndef db_session():\n    session = TestingSessionLocal()\n    try:\n        yield session\n    finally:\n        session.rollback()\n        session.close()\n\n@pytest.fixture\ndef client(db_session):\n    def override_get_db():\n        yield db_session\n    app.dependency_overrides[get_db] = override_get_db\n    with TestClient(app) as c:\n        yield c\n    app.dependency_overrides.clear()\n```\n\nRule of thumb: roll back the test session instead of committing — it gives\neach test an isolated, empty state without truncating tables.\n",{"id":190,"difficulty":35,"q":191,"a":192},"override-external-api","How do you mock an external HTTP API call injected as a dependency?","Inject the HTTP client as a dependency, then override it in tests:\n\n```python\n# In app code\nimport httpx\n\nasync def get_http_client() -> httpx.AsyncClient:\n    async with httpx.AsyncClient() as client:\n        yield client\n\n@app.get(\"\u002Fweather\")\nasync def weather(city: str, client: httpx.AsyncClient = Depends(get_http_client)):\n    resp = await client.get(f\"https:\u002F\u002Fapi.weather.com\u002F{city}\")\n    return resp.json()\n```\n\n```python\n# In tests — replace with a respx mock\nimport respx\nimport httpx\n\n@respx.mock\ndef test_weather(client):\n    respx.get(\"https:\u002F\u002Fapi.weather.com\u002FLondon\").mock(\n        return_value=httpx.Response(200, json={\"temp\": 15})\n    )\n    resp = client.get(\"\u002Fweather?city=London\")\n    assert resp.json()[\"temp\"] == 15\n```\n\nOr inject a fake client via override:\n```python\nasync def fake_http_client():\n    yield FakeAsyncClient()\n\napp.dependency_overrides[get_http_client] = fake_http_client\n```\n\nRule of thumb: inject HTTP clients as dependencies rather than instantiating\nthem inside handlers — it makes them mockable without `patch()`.\n",{"id":194,"difficulty":105,"q":195,"a":196},"partial-override","How do you override only part of a dependency chain (one level deep)?","Override just the sub-dependency, leaving higher-level deps intact:\n\n```python\n# Dependency chain: get_db → get_current_user → require_admin\n# We want to test require_admin with a specific user but real DB logic\n\ndef fixed_user():\n    return User(id=99, name=\"Test Admin\", role=\"admin\")\n\n# Override only get_current_user — get_db still uses real DI\napp.dependency_overrides[get_current_user] = fixed_user\n\n# require_admin still calls its Depends(get_current_user) — but gets our mock\n```\n\nFastAPI resolves the override at the point where the original dep is declared —\nanything that `Depends()` on it gets the override's return value.\n\nRule of thumb: override at the lowest practical level — overriding `get_current_user`\n(not `require_admin`) tests `require_admin`'s logic with controlled user data.\n",{"id":198,"difficulty":35,"q":199,"a":200},"class-dep-override","How do you override a class-based dependency in FastAPI tests?","Class-based deps are instantiated by FastAPI on each call. Override with another\ncallable (class, function, or lambda) that returns a compatible object:\n\n```python\nclass PaginationDep:\n    def __init__(self, page: int = 1, size: int = 20):\n        self.skip = (page - 1) * size\n        self.limit = size\n\n# Override with a fixed pagination\nclass FixedPagination:\n    skip = 0\n    limit = 5\n\napp.dependency_overrides[PaginationDep] = FixedPagination\n\ndef test_first_page(client):\n    resp = client.get(\"\u002Fitems\")\n    data = resp.json()\n    assert len(data) \u003C= 5\n```\n\nRule of thumb: match the override's public interface (attributes\u002Fmethods your\nhandler uses) rather than its constructor — duck typing is sufficient.\n",{"id":202,"difficulty":35,"q":203,"a":204},"override-scope-per-test","How do you apply a dependency override to only one test without affecting others?","Use a pytest fixture with function scope (the default):\n\n```python\n@pytest.fixture\ndef admin_override():\n    app.dependency_overrides[get_current_user] = lambda: {\"id\": 1, \"role\": \"admin\"}\n    yield\n    del app.dependency_overrides[get_current_user]\n\ndef test_admin_only(client, admin_override):\n    resp = client.delete(\"\u002Fusers\u002F99\")\n    assert resp.status_code == 200\n\ndef test_normal_user(client):\n    # admin_override not active — real get_current_user used\n    resp = client.delete(\"\u002Fusers\u002F99\")\n    assert resp.status_code == 403\n```\n\nRule of thumb: use per-test fixtures with explicit teardown for scoped overrides —\ndon't set overrides directly in test bodies without a cleanup mechanism.\n",{"id":206,"difficulty":105,"q":207,"a":208},"verify-dep-called","How do you verify that a dependency was called with specific arguments in a test?","Replace the dependency with a `MagicMock` or a spy function:\n\n```python\nfrom unittest.mock import MagicMock, call\n\nmock_audit = MagicMock()\n\ndef audit_override(request: Request, user = Depends(get_current_user)):\n    mock_audit(path=str(request.url), user_id=user[\"id\"])\n\napp.dependency_overrides[audit_dep] = audit_override\n\ndef test_audit_logged(client):\n    client.get(\"\u002Fitems\")\n    mock_audit.assert_called_once()\n    call_args = mock_audit.call_args\n    assert call_args.kwargs[\"user_id\"] == 1\n```\n\nRule of thumb: spy on dependencies rather than internal functions — testing\nthrough the DI graph tests the real integration path.\n",{"id":210,"difficulty":105,"q":211,"a":212},"dependency-override-with-yield","Can you use a yield function as a dependency override?","Yes — yield-based overrides work exactly like regular yield dependencies:\n\n```python\nclass FakeDB:\n    def __init__(self):\n        self.data = [{\"id\": 1, \"name\": \"Alice\"}]\n\n    def get_all(self):\n        return self.data\n\nasync def fake_get_db():\n    db = FakeDB()\n    db.data.append({\"id\": 2, \"name\": \"Bob\"})  # setup\n    yield db\n    db.data.clear()                              # teardown (after handler)\n\napp.dependency_overrides[get_db] = fake_get_db\n```\n\nThe teardown (after `yield`) still runs after the handler completes — useful for\nresetting state in the override itself.\n\nRule of thumb: use yield overrides when the fake resource needs setup and\ncleanup; use simple lambdas\u002Ffunctions for stateless fakes.\n",{"description":32},"FastAPI dependency override interview questions — app.dependency_overrides, isolating tests, mocking auth, DB session swapping and cleanup patterns.","fastapi\u002Ftesting\u002Fdependency-overrides","175Uw5rR-p9_L-Whet4tK7RU-i9X1_m80vF3wA-Egnk",1782244096254]