深夜,程序员小王对着一条条的错误信息发愁。
他的 FastAPI 应用程序明明在服务器上运行良好,但一旦运行测试,就连最简单的健康检查都报错。
这不是他一个人的战斗,而是许多开发者面临的共同困境。
问题根源在于:测试环境与生产环境的纠缠。
测试与生产的 “隔离” 难题
很多开发者对测试抱有误解:
- 以为用了
pytest就是真测试 - 以为跑通了就是没问题了
- 以为 “测试数据库” 只是个概念
直到某天,测试删光了用户表,或是性能测试拖垮了线上服务。
才恍然大悟:测试环境和生产环境根本没有隔离。
FastAPI 应用非常容易踩坑,在测试时,若不加注意,就会直接调用生产环境。
FastAPI 测试的正确打开方式:隔离、模拟、覆盖
真正的测试的三个核心要素:
- 隔离的测试数据库 — 绝不碰生产数据
- 模拟的依赖项 — 控制测试环境的所有输入
- 覆盖的依赖注入 — 让 FastAPI 在测试时,换 “演员
00、准备
安装依赖:
pip install httpx -i https://pypi.tuna.tsinghua.edu.cn/simple
重点注意:
本期,需要使用 IDE 打开 Chapter_14 目录(TodoApp 目录上一级)
项目根目录变了,项目中所有的导入路径,都需要调整。这里很麻烦,需要一个一个的去改。
此处省略一万字 ......。
大家记得找我要配套的项目代码。直接私信我,发送 FastAPI
修改完成后,在终端启动应用程序
uvicorn TodoApp.main:app --reload
程序运行正常,就算完成了。
01、创建专属测试数据库
进入 TodoApp/test 目录,创建 test_todos.py 文件(针对 todos.py 文件进行测试)
在文件中添加测试数据库地址、测试引擎、测试会话等,这些属于测试环境,与生产环境相隔离。
from sqlalchemy import create_engine
from sqlalchemy.pool import StaticPool
from sqlalchemy.orm import sessionmaker
from ..database import Base
# 测试数据库地址
SQLALCHEMY_DATABASE_URL = "sqlite:///./testdb.db"
# 创建测试引擎,StaticPool确保连接复用
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
connect_args={"check_same_thread": False},
poolclass=StaticPool
)
# 创建测试会话
TestSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base.metadata.create_all(bind=engine)
02、覆盖数据库依赖
用测试会话替换生产的数据库会话,这样测试时就会连接测试数据库
# 覆盖数据库依赖
def override_get_db():
db = TestingSessionLocal()
try:
yield db
finally:
db.close()
# 告诉 FastAPI:测试时用这些替代品
app.dependency_overrides[get_db] = override_get_db
03、Mock 已登录用户
很多接口需要用户登录才能访问,直接测试会报错,我们可以模拟用户信息绕过登录验证。
# 覆盖当前用户依赖(无需真实登录!)
def override_get_current_user():
return {
"username": "wangerge",
"id": 1,
"user_role": "admin"
}
# 告诉 FastAPI:测试时用这些替代品
app.dependency_overrides[get_current_user] = override_get_current_user
做完这三步,就可以测试需要数据库和登录的接口了。
04、编写接口测试
添加待办事项列表接口测试
client = TestClient(app)
def test_read_all_authenticated():
response = client.get("/todos")
assert response.status_code == status.HTTP_200_OK
assert response.json() == []
我们在终端,切换到 Chapter_14 目录,执行接口测试:
(.venv) wangerge_notes: Chapter_14$ pytest --disable-warnings
==================== test session starts ====================
collected 3 items
TodoApp/test/test_example.py . [ 33%]
TodoApp/test/test_main.py . [ 66%]
TodoApp/test/test_todos.py . [100%]
==================== 3 passed, 2 warnings in 2.82s ====================
(.venv) wangerge_notes: Chapter_14$
这样,测试一切正常。
写在最后
测试不是 CheckList,不是 “写完就行” 的任务。它是代码的镜子,是质量的守护者。
从今天开始,重建你对测试的信任 —— 从配置一个隔离的测试环境开始。
接下来,我们将一起讨论:创建数据接口的测试要怎么写?删除数据接口要怎么写?如果数据没找到时,接口测试要怎么写?
下期,我将掰开了,揉碎了,把它们一次性讲清楚。
想要获取本章完整代码,请在评论区回复 【FastAPI】,代码直接复制就能跑。
关于 FastAPI 的其他疑问
新功能上线就崩?Pytest三步测试法,让你的FastAPI稳如老狗,Bug率直降80%
加个字段,服务崩了?FastAPI新手避坑,Alembic三步搞定表结构变更!方案闭眼抄
别等着被骂:API上线前,一定要把SQLite换成MySQL,附 FastAPI对接代码
别等被骂才后悔:APP上线前,一定要把SQLite换成PostgreSQL,附 FastAPI对接代码
你的API在裸奔?踩坑8小时,从“越权裸奔”到“权限严控”:FastAPI+JWT+依赖注入,这套方案闭眼抄
相关内容我都给大家做好了,感兴趣的朋友来「我的主页」找一找,直接就可以看到。
欢迎关注 「王二哥的技术笔记」,每天分享「Python」、「职场」有趣干货,千万不要错过!