用 pytest 给 FastAPI 写最小集成测试:覆盖成功、校验与错误响应
接口能启动,只能说明应用进程起来了;接口能返回一次成功响应,也不代表参数校验和错误处理可靠。把 HTTP 请求写成自动化测试,可以在改动后快速检查状态码、响应结构和边界行为。下面用 FastAPI 自带的 TestClient 演示一组不需要启动服务器的进程内测试。
1. 安装测试依赖
在项目使用的虚拟环境中安装:
pip install fastapi pytest httpx
FastAPI 的 TestClient 通过 ASGI 应用直接发请求,不需要先运行 uvicorn,也不需要云资源。它适合检查路由、请求校验和响应序列化;真实网络、反向代理和部署配置仍需另行验证。
2. 准备一个小接口
例如在 app/main.py 中定义创建商品的接口:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
class ItemCreate(BaseModel):
name: str
price: float
@app.post("/items", status_code=201)
def create_item(item: ItemCreate):
if item.price < 0:
raise HTTPException(status_code=400, detail="price must be non-negative")
return {"id": 1, **item.model_dump()}
@app.get("/health")
def health():
return {"status": "ok"}
示例把存储省略了,重点是把三种结果区分开:成功创建、请求字段不符合模型、业务规则拒绝请求。实际项目可把业务规则放到服务层,路由只负责接收与返回。
3. 用 TestClient 覆盖三种结果
在项目根目录创建 tests/test_items.py:
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
def test_health_returns_ok():
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "ok"}
def test_create_item_returns_created_item():
response = client.post(
"/items",
json={"name": "keyboard", "price": 199.0},
)
assert response.status_code == 201
assert response.json() == {
"id": 1,
"name": "keyboard",
"price": 199.0,
}
def test_missing_price_is_rejected_by_validation():
response = client.post("/items", json={"name": "keyboard"})
assert response.status_code == 422
assert response.json()["detail"]
def test_negative_price_returns_business_error():
response = client.post(
"/items",
json={"name": "keyboard", "price": -1},
)
assert response.status_code == 400
assert response.json()["detail"] == "price must be non-negative"
这几项断言各自保护不同契约。健康检查确认基础路由和 JSON 响应;成功用例检查创建状态码及字段;缺少价格时返回 422,说明请求模型校验生效;负数价格返回 400,说明业务错误没有被误当成成功。不要只断言“状态码不是 500”,那样会漏掉响应结构或错误类型变化。
4. 运行并读懂结果
在项目根目录执行:
pytest -q
测试通过后,pytest 会显示通过数量;失败时先看具体断言,再检查实际状态码和响应 JSON。若导入时报错,确认当前目录是项目根目录、包路径正确,并且运行 pytest 的 Python 与安装依赖的虚拟环境一致。
5. 有数据库或外部服务时隔离副作用
测试不要连生产数据库,也不要真的发短信、邮件或扣款。常见做法是把数据库依赖替换成测试实现、为每个用例准备独立数据,并在结束时回滚或清理;外部 HTTP 服务则用 mock 固定响应。这样测试结果可重复,也不会让一次本地验证改动真实业务数据。
TestClient 能验证应用层的 HTTP 行为,但不能替代部署后的端到端检查。发布前仍应在目标环境确认进程监听地址、代理转发、环境变量和依赖服务连接。把这两层检查分开,能更快判断问题是在代码契约还是运行环境。
- 点赞
- 收藏
- 关注作者
评论(0)