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_overridesreplaces it. Use the same object as the route:require()andoptional()return copies, so assign the copy to a name first, asadminis here. test_admin_requires_a_token- Check the protection itself: status code and
WWW-Authenticateheader. test_login_then_me- Session cookies are
Secure, so the test client needs anhttps://base URL to send them back.
To make sure no route is left unprotected, see the audit recipe.