(十)FastAPI的测试与调试
测试和调试是开发高质量应用程序的关键部分。FastAPI 提供了多种工具和方法,使测试和调试过程更加高效和简便。本文将详细介绍如何使用这些工具和方法,帮助你编写高质量的代码。
1. 使用 pytest
进行测试
pytest
是一个强大的测试框架,可以轻松地编写和运行测试。首先,安装 pytest
:
pip install pytest
创建一个简单的 FastAPI 应用 main.py
:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello, World!"}
编写测试文件 test_main.py
:
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_read_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello, World!"}
运行测试:
pytest
上面的例子展示了如何使用pytest
和TestClient
测试 FastAPI 应用的基本请求和响应。通过使用断言语句,可以验证 API 返回的状态码和数据是否符合预期。
2. 测试依赖注入
依赖注入是 FastAPI 的强大功能,通过依赖注入,可以在测试中覆盖依赖项,从而测试不同的场景。例如:
from fastapi import Depends, FastAPI, HTTPException
app = FastAPI()
def get_token_header():
return "fake-token"
@app.get("/items/")
async def read_items(token: str = Depends(get_token_header)):
if token != "fake-token":
raise HTTPException(status_code=400, detail="Invalid token")
return {"items": ["item1", "item2"]}
在测试文件中,可以覆盖get_token_header
依赖项:
# test_main.py
from fastapi.testclient import TestClient
from main import app, get_token_header
app.dependency_overrides[get_token_header] = lambda: "test-token"
client = TestClient(app)
def test_read_items():
response = client.get("/items/")
assert response.status_code == 400
assert response.json() == {"detail": "Invalid token"}
这种方式允许我们在测试中模拟不同的依赖项,从而测试不同的场景和错误处理逻辑。
3. 使用 TestClient
进行集成测试
TestClient
可以模拟 HTTP 请求,进行集成测试。下面是一个更复杂的例子:
# main.py
from fastapi import FastAPI, Depends, HTTPException
app = FastAPI()
def fake_db():
return {"username": "test"}
@app.get("/users/me")
async def read_users_me(db=Depends(fake_db)):
return db
在测试文件中,可以使用TestClient
模拟请求:
# test_main.py
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_read_users_me():
response = client.get("/users/me")
assert response.status_code == 200
assert response.json() == {"username": "test"}
在这个例子中,fake_db
函数模拟了一个数据库依赖项,通过覆盖依赖项和使用 TestClient,可以方便地进行集成测试。
4. 调试 FastAPI 应用
调试是发现和修复错误的重要过程。可以使用 uvicorn
的 --reload
选项来自动重新加载代码,使用 pdb
等调试工具进行断点调试。
使用 --reload
选项启动 FastAPI 应用:
uvicorn main:app --reload
在代码中插入断点进行调试:
from fastapi import FastAPI, Depends, HTTPException
app = FastAPI()
def fake_db():
return {"username": "test"}
@app.get("/users/me")
async def read_users_me(db=Depends(fake_db)):
import pdb; pdb.set_trace() # 插入断点
return db
使用 pdb
可以在运行时暂停程序,并进入交互式调试环境,检查变量和程序状态。
常用 pdb
命令
在调试模式下,你可以使用以下命令来检查和控制程序执行:
- n (next):执行下一行代码。
- c (continue):继续执行程序直到下一个断点。
- s (step):进入函数内部,逐步执行。
- l (list):显示当前代码行和周围的代码。
- p (print):打印变量值,例如 p variable_name。
- q (quit):退出调试模式并终止程序。
5. 使用 HTTPException
和自定义异常处理
FastAPI 提供了 HTTPException
类,可以在请求处理过程中抛出 HTTP 异常。例如:
from fastapi import HTTPException
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id == 0:
raise HTTPException(status_code=404, detail="Item not found")
return {"item_id": item_id}
在测试中,可以验证异常处理逻辑:
# test_main.py
def test_read_item_not_found():
response = client.get("/items/0")
assert response.status_code == 404
assert response.json() == {"detail": "Item not found"}
自定义异常处理可以通过 @app.exception_handler
装饰器实现:
from fastapi import Request, FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
class CustomException(Exception):
def __init__(self, name: str):
self.name = name
@app.exception_handler(CustomException)
async def custom_exception_handler(request: Request, exc: CustomException):
return JSONResponse(
status_code=418,
content={"message": f"Oops! {exc.name} did something. There goes a custom error."},
)
@app.get("/cause_error")
async def cause_error():
raise CustomException(name="FastAPI")
测试自定义异常处理:
# test_main.py
def test_custom_exception():
response = client.get("/cause_error")
assert response.status_code == 418
assert response.json() == {"message": "Oops! FastAPI did something. There goes a custom error."}
6. 性能测试
性能测试可以使用工具如 locust
或 ab
(Apache Benchmark) 来测试应用的性能。以 locust 为例:
- 安装
locust
:
pip install locust
- 创建
locustfile.py
:
from locust import HttpUser, task, between
class QuickstartUser(HttpUser):
wait_time = between(1, 5)
@task
def hello_world(self):
self.client.get("/")
self.client.get("/users/me")
- 运行
locust
:
locust
- 打开浏览器,访问
http://localhost:8089
,配置并启动测试。
7. 常见问题和解决方案
- 依赖注入的问题:测试时覆盖依赖项,确保每个测试独立运行。
- 数据库测试:使用测试数据库,确保测试环境与生产环境隔离。
- 性能问题:使用性能分析工具,找出瓶颈。
总结
测试和调试是开发过程中不可或缺的环节。通过本文介绍的方法和工具,你可以更高效地测试和调试 FastAPI 应用,确保代码质量和稳定性。希望本文对你有所帮助,助你写出高质量的 FastAPI 应用。
转载自:https://juejin.cn/post/7380579027415367730