FastAPI 系列
测试怎么写才不连真实库(当前篇)
接口测试应验证状态码、JSON 形状和鉴权分支,而不是验证 Postgres 是否在线。TestClient 在进程内打 ASGI,dependency_overrides 把 get_db / get_current_user 换成假对象。真实数据库留给少量集成测试。

最小测试
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
def test_health():
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "ok"}
相对导入很重要:测试文件应能 from app.main import app,而不是把项目根随便塞进 sys.path。
覆盖数据库依赖
from app.db import get_db
class FakeSession:
def get(self, model, item_id):
if item_id == 1:
return {"id": 1, "name": "demo"}
return None
def override_get_db():
yield FakeSession()
def test_read_item(client):
app.dependency_overrides[get_db] = override_get_db
response = client.get("/items/1")
assert response.status_code == 200
app.dependency_overrides.clear()
用 pytest fixture 做 setup/teardown,避免测试互相污染 overrides。
覆盖当前用户
from app.auth import get_current_user
def test_me_ok():
app.dependency_overrides[get_current_user] = lambda: User(username="alice")
response = client.get("/users/me")
assert response.status_code == 200
assert response.json()["username"] == "alice"
app.dependency_overrides.clear()
def test_me_unauthorized():
response = client.get("/users/me")
assert response.status_code == 401
未覆盖时,OAuth2PasswordBearer 会因缺少 Authorization 返回 401,这正好覆盖「没带 Token」分支。不要为了省事在测试里把鉴权中间件拆掉。
校验错误也要测
def test_create_item_invalid():
response = client.post("/items/", json={"name": ""})
assert response.status_code == 422
assert response.json()["detail"]
422 的结构是契约的一部分。改了模型约束,测试应一起红。
常见误区
每个测试都启动 uvicorn 再 curl
慢、端口冲突、难并行。TestClient 就是为这个存在的。
覆盖错对象
必须覆盖定义 Depends(get_db) 时用的那个函数对象。复制粘贴了一个同名函数不会生效。
测试依赖真实 JWT 密钥
单测覆盖 get_current_user;另写一两个测试专门喂过期 Token,不必让所有用例都走加密。
小结
单测替换依赖,集成测试才碰真实库。下一篇把 fastapi dev 换成可水平扩展的生产启动方式。
参考资料
测试怎么写才不连真实库:TestClient 与 dependency_overrides
https://lautung.com/archives/fastapi-11-testing
评论