如何用FastAPI和Pytest实现拒绝裸奔的自动化测试实战?

摘要:1. 引言:为什么你需要雇佣一群“机器人”? 你是否经历过这种绝望: 你刚刚修复了一个“用户无法登录”的 Bug,满怀信心地推上线。结果两分钟后,老板打电话吼道:“为什么现在的用户没法注册了?!” 这就是典型的回归缺陷(Regression
1. 引言:为什么你需要雇佣一群“机器人”? 你是否经历过这种绝望: 你刚刚修复了一个“用户无法登录”的 Bug,满怀信心地推上线。结果两分钟后,老板打电话吼道:“为什么现在的用户没法注册了?!” 这就是典型的回归缺陷(Regression Bug)——修了旧的,坏了新的。 手动测试(用 Postman 一个个点)就像是让主厨在每道菜端出去前都亲自尝一口。这在小餐馆(小项目)行得通,但如果是流水线工厂(大项目),主厨会被撑死,或者因为味觉疲劳而漏掉变质的菜。 自动化测试(Pytest) 就像是雇佣了一万个不知疲倦的机器人。你每改一行代码,它们就能在几秒钟内把所有菜品(API)全部尝一遍,并告诉你:“老板,酸辣汤(登录接口)咸了!”
2. 概念拆解:TestClient 与“替身演员” FastAPI 的测试之所以简单,是因为它提供了一个神器:TestClient。 核心机制:TestClient 想象一下,通常你测试 API 需要启动服务器,然后用 HTTP 请求去撞它。 而 TestClient 是一种欺骗手段。它不需要真的启动网络服务,它直接通过 Python 代码调用你的 FastAPI 应用函数。 速度极快:没有网络延迟。 同步写法:即使你的 API 是 async 的,测试代码也可以写成普通的同步代码(它是基于 httpx 的)。 核心策略:依赖覆盖(Dependency Override) 这是 FastAPI 测试的杀手锏。还记得我们在“最佳实践”里提到的依赖注入吗? 在测试时,我们不希望操作真实的生产数据库,也不希望真的发送短信验证码。 我们可以用替身(Mock/Override) 来替换掉真实的组件。
3. 动手实战:由浅入深 3.0 准备工作 首先,我们需要安装测试界的“瑞士军刀”: Bash pip install pytest httpx 3.1 Hello World 测试 (MVP) 假设你的 main.py 是这样的: Python # main.py from fastapi import FastAPI app = FastAPI() @app.get("/") async def read_main(): return {"msg": "Hello World"} 我们在同级目录下创建一个 test_main.py: Python # test_main.py from fastapi.testclient import TestClient from main import app # 导入你的 app 对象 # 1. 创建测试客户端 client = TestClient(app) # 2. 编写测试函数(必须以 test_ 开头) def test_read_main(): # Act: 模拟发送请求 response = client.get("/") # Assert: 断言(验证结果是否符合预期) assert response.status_code == 200 assert response.json() == {"msg": "Hello World"} 运行测试: 在终端输入 pytest。你会看到迷人的绿色字体,显示测试通过。 3.2 进阶深潜:搞定数据库测试 (The Real Challenge) 这才是大多数人卡住的地方。如果 API 连了数据库,怎么测? 绝对不要连接生产库测试! 也不要连接开发库,因为测试产生的数据(比如 test_user_1)会污染环境。 解决方案:使用 dependency_overrides 将数据库替换为 SQLite 内存数据库(跑完即焚)。
阅读全文