文章列表
2 分钟阅读

FastAPI 项目测试指南:pytest、TestClient、依赖覆盖怎么用

更新说明:新增 FastAPI 测试实践。


系列:Python Web 工程实践

第 5 / 8 篇

  1. Python Web 项目配置管理:环境变量、.env 和生产配置怎么拆
  2. Python Web 项目如何连接数据库:SQLAlchemy、Django ORM、迁移怎么选
  3. Alembic 数据库迁移入门:表结构变更怎么安全上线
  4. Django 数据库迁移实战:makemigrations 和 migrate 背后的坑
  5. FastAPI 项目测试指南:pytest、TestClient、依赖覆盖怎么用
  6. Django 测试入门:Model、View、API 测试怎么写
  7. FastAPI 分层架构:router、service、repository 怎么拆
  8. PostgreSQL 基础:索引、事务、慢查询怎么理解

FastAPI 项目写测试时,最先要覆盖的不是工具函数,而是接口行为:请求进来,依赖被注入,数据库被访问,最后返回什么状态码和 JSON。

可以先读 FastAPI 安装与使用指南FastAPI 进阶使用指南,再回来看测试会更顺。 如果项目已经开始拆 router、service、repository,可以同时参考 FastAPI 分层架构:router、service、repository 怎么拆,测试会更容易落到稳定边界上。

最小接口测试

FastAPI 自带的测试体验很直接。

tests/test_health.py
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"}

运行:

Terminal window
pytest

接口测试要尽量写业务结果,不要只判断“没有报错”。

覆盖依赖

FastAPI 的依赖注入适合测试。比如接口依赖当前用户:

app/deps.py
def get_current_user():
...

测试时可以覆盖它:

tests/test_articles.py
from app.deps import get_current_user
from app.main import app
def fake_user():
return {"id": 1, "name": "tester"}
def test_create_article(client):
app.dependency_overrides[get_current_user] = fake_user
response = client.post("/articles", json={"title": "hello"})
assert response.status_code == 201
app.dependency_overrides.clear()

更稳一点的做法是用 fixture 清理覆盖,避免影响后面的测试。

tests/conftest.py
import pytest
from app.main import app
@pytest.fixture(autouse=True)
def clear_overrides():
yield
app.dependency_overrides.clear()

测试数据库

不要让测试打到开发库。至少要准备单独的测试库,或者用临时 SQLite。

tests/conftest.py
@pytest.fixture
def client(test_session):
def override_session():
yield test_session
app.dependency_overrides[get_session] = override_session
return TestClient(app)

如果项目已经用了 SQLAlchemy 和 Alembic,测试库结构最好由迁移创建,而不是手写一套表结构。

鉴权接口怎么测

鉴权测试至少覆盖三类:

  • 没有 token 返回 401
  • token 无效返回 401
  • 权限不足返回 403
def test_private_api_requires_login(client):
response = client.get("/me")
assert response.status_code == 401

具体登录和 JWT 可以接上 FastAPI 项目实战:用户登录与 JWT 鉴权

测试写到什么程度

我一般先覆盖这些路径:

  • 健康检查
  • 登录和鉴权
  • 核心 CRUD
  • 参数校验失败
  • 权限不足
  • 数据不存在

总结

测试不需要一次写满。先把最容易线上出问题的接口覆盖住,再慢慢补边界。FastAPI 的依赖覆盖很好用,但用完要及时清理,避免一个测试影响另一个测试。