薏米短剧正版
46.7MB · 2025-10-21
FastAPI提供了强大的测试工具TestClient,它允许我们直接测试API接口而无需启动完整服务。TestClient的核心原理是模拟HTTP客户端请求,并直接调用FastAPI应用程序的路由处理器。
[用户请求]
↓
[TestClient] → [FastAPI应用路由]
↓
[模拟HTTP响应] → [断言验证]
首先需要安装测试依赖:
pip install fastapi==0.109.1 pytest==7.4.3 httpx==0.25.2
基本测试代码示例:
from fastapi.testclient import TestClient
from main import app # 导入你的FastAPI应用实例
client = TestClient(app)
def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello World"}
在FastAPI中,响应验证确保API返回数据的结构和类型完全符合预期,Pydantic模型是该功能的核心实现机制。
[API请求]
↓
[路由处理器] → [返回数据]
↓
[Pydantic响应模型] → [数据验证]
↓
[通过:返回JSON] / [失败:422错误]
from pydantic import BaseModel
from fastapi import FastAPI, status
app = FastAPI()
class UserResponse(BaseModel):
id: int
name: str
email: str
is_active: bool
@app.get("/users/{user_id}", response_model=UserResponse)
async def read_user(user_id: int):
# 模拟数据库查询
return {
"id": user_id,
"name": "John Doe",
"email": "[email protected]",
"is_active": True,
# 如果包含extra_field,Pydantic会自动过滤
}
# 测试代码
def test_user_response_validation():
response = client.get("/users/1")
assert response.status_code == status.HTTP_200_OK
# 验证响应结构
user = response.json()
assert "id" in user
assert "name" in user
assert "email" in user
assert "is_active" in user
assert isinstance(user["id"], int)
assert isinstance(user["is_active"], bool)
# 检测多余字段
assert "extra_field" not in user
pytest-cov
工具统计覆盖率:pip install pytest-cov==4.1.0
pytest --cov=app tests/
def test_invalid_user():
response = client.get("/users/9999")
assert response.status_code == status.HTTP_404_NOT_FOUND
使用unittest.mock
模拟外部服务:
from unittest.mock import patch
def test_external_service():
with patch("module.external_service") as mock_service:
mock_service.return_value = {"result": "mocked"}
response = client.get("/external-api")
assert response.json() == {"data": "mocked"}
▲
/ 端到端测试(5-10%)
/
------- 集成测试(15-20%)
------- 单元测试(70-80%)
project/
├── app/
│ ├── main.py
│ ├── routers/
│ └── models.py
└── tests/
├── unit/
│ ├── test_routers.py
│ └── test_models.py
└── integration/
└── test_auth.py
import pytest
from fastapi import HTTPException
# 参数化测试多种场景
@pytest.mark.parametrize("user_id,expected_status", [
(1, 200),
(0, 422),
(-1, 422),
(999, 404)
])
def test_user_endpoints(user_id, expected_status):
response = client.get(f"/users/{user_id}")
assert response.status_code == expected_status
# 测试异常处理
def test_exception_handling():
with pytest.raises(HTTPException) as exc_info:
# 触发异常的条件
raise HTTPException(status_code=400, detail="Bad request")
assert exc_info.value.status_code == 400
assert "Bad request" in exc_info.value.detail
问题1:当Pydantic响应模型验证失败时,FastAPI会返回什么状态码?
A) 200 B) 400 C) 422 D) 500
问题2:如何有效测试需要访问数据库的路由?
A) 每次都访问真实数据库
B) 使用内存数据库
C) 创建模拟对象(Mock)
D) 禁用该测试
答案解析:
原因分析:
解决方案:
response_model = UserResponse
class StrictModel(BaseModel):
class Config:
extra = "forbid" # 禁止额外字段
myapp --reload
时观察自动生成的文档验证预防措施:
# 测试中注入认证token
def test_protected_route():
response = client.get(
"/protected",
headers={"Authorization": "Bearer test_token"}
)
assert response.status_code == 200
调试建议:
import logging
logging.basicConfig(level=logging.DEBUG)
@app.middleware("http")
async def catch_errors(request, call_next):
try:
return await call_next(request)
except Exception as e:
# 记录详细错误信息
logger.exception(e)
return JSONResponse(status_code=500)