Skip to content

Testing

Given this app:

main.py
import os

from fastapi import FastAPI, Response, Security

from fastapi_multiauth import APIKeyCookieAuth, HTTPBearerAuth, UnauthorizedError

SECRET_KEY = os.environ["SECRET_KEY"]


async def validate_token(token: str) -> str:
    raise UnauthorizedError()


async def validate_session(username: str) -> str:
    return username


bearer = HTTPBearerAuth(validator=validate_token)
session = APIKeyCookieAuth(
    name="__Host-session", validator=validate_session, secret_key=SECRET_KEY
)
admin = bearer.require(role="admin")

app = FastAPI()


@app.post("/login")
async def login(response: Response):
    session.set_cookie(response, "alice")
    return {"ok": True}


@app.get("/me")
async def me(username: str = Security(session)):
    return {"username": username}


@app.get("/admin")
async def admin_page(username: str = Security(admin)):
    return {"admin": username}

Here are three ways to test it:

test_main.py
from fastapi.testclient import TestClient

from .main import admin, app


def test_admin_with_override():
    app.dependency_overrides[admin] = lambda: "alice"
    try:
        response = TestClient(app).get("/admin")
    finally:
        app.dependency_overrides.clear()
    assert response.json() == {"admin": "alice"}


def test_admin_requires_a_token():
    response = TestClient(app).get("/admin")
    assert response.status_code == 401
    assert response.headers["www-authenticate"].startswith("Bearer")


def test_login_then_me():
    client = TestClient(app, base_url="https://testserver")
    client.post("/login")
    assert client.get("/me").json() == {"username": "alice"}
test_admin_with_override
A source is a normal FastAPI dependency, so app.dependency_overrides replaces it. Use the same object as the route: require() and optional() return copies, so assign the copy to a name first, as admin is here.
test_admin_requires_a_token
Check the protection itself: status code and WWW-Authenticate header.
test_login_then_me
Session cookies are Secure, so the test client needs an https:// base URL to send them back.

To make sure no route is left unprotected, see the audit recipe.