切换日光/暗黑模式
068. 测试覆盖率、conftest 与事件循环
学习目标
这一节回到自动化测试。
学完后,你应该能理解:
- 为什么要配置测试覆盖率;
conftest.py如何提供统一测试能力;- 为什么测试客户端要直接挂载 FastAPI 应用;
- PyTest 异步测试里的事件循环差异;
- Redis 连接池为什么会被事件循环影响。
测试覆盖率
自动化测试不只是验证接口能不能跑通。
还要知道代码里哪些行被测试执行过。
这就是测试覆盖率。
覆盖率工具会在跑测试时记录:
- 哪些文件被执行;
- 哪些函数被执行;
- 哪些分支没有被测试覆盖。
它不能证明代码完全没问题。
但能提示你哪些核心逻辑还没有测试保护。
pyproject.toml 测试配置
测试覆盖率通常会放进项目配置。
例如:
toml
[tool.pytest.ini_options]
addopts = "--cov=app --cov-report=term-missing"这样每次跑测试时,都会顺带输出覆盖率报告。
term-missing 会把未覆盖的行列出来。
这对后续补测试很有用。
conftest.py
conftest.py 是 PyTest 的公共配置文件。
它适合放测试夹具。
夹具可以提供:
- 测试客户端;
- 测试用户;
- Token;
- 数据库清理逻辑;
- Redis 或缓存替身;
- 公共请求头。
这样每个测试文件不用重复准备同一套环境。
直接挂载 FastAPI 应用
测试接口有两种方式。
一种是先启动后端服务,再用 HTTP 地址请求它。
另一种是测试客户端直接挂载 FastAPI 的 app 实例。
课程里使用后者。
好处是测试过程能统计到接口内部代码覆盖率。
如果只是请求一个外部运行中的服务,覆盖率工具不一定知道服务端执行了哪些代码。
测试 Token
认证中间件已经接入以后,很多接口都需要 Token。
所以测试夹具里会提前生成一个可用 Token。
请求时再把它放进请求头:
http
Authorization: Bearer <token>这样业务接口测试不用每次都重新走登录流程。
异步测试的事件循环
FastAPI 和很多 Python 后端库都运行在异步事件循环上。
可以把它类比成前端事件循环。
只是 Python 在不同系统上的实现细节会有差异。
PyTest 跑异步测试时,为了隔离不同测试用例,可能会给每个用例创建单独的事件循环。
这能减少测试之间互相影响。
但也会影响依赖事件循环的全局对象。
Redis 连接池问题
Redis 工具类通常会做成全局单例。
原因是 Redis 客户端内部有连接池。
正常服务运行时,一个全局工具类就可以反复从连接池里拿连接。
但在测试里,如果每个测试用例使用不同事件循环,连接池绑定的旧事件循环关闭后,Redis 客户端可能失效。
这就是测试环境和真实服务环境的差异。
测试环境的处理方式
测试环境可以特殊处理 Redis 客户端。
例如:
- 正式运行时继续复用连接池;
- 测试运行时按需创建新客户端;
- 用完后不依赖旧事件循环继续复用。
这不是为了让业务代码变复杂。
而是为了让自动化测试稳定。
文件命名也会影响测试
PyTest 会根据命名规则识别测试文件。
通常测试文件需要以 test_ 开头或以 _test.py 结尾。
如果测试目录里有普通 Python 文件,导入顺序和包识别可能会和预期不同。
当出现模块找不到、循环导入、夹具不生效时,要先检查文件命名和目录标记。
这一节的重点
这一节把测试环境搭得更像工程项目。
你需要记住:
- 覆盖率帮助发现未测试代码;
conftest.py用来集中准备测试上下文;- 直接挂载
app实例更利于覆盖率统计; - 异步测试可能每个用例有独立事件循环;
- Redis 连接池在测试里要处理事件循环生命周期;
- 测试文件命名会影响 PyTest 的识别和导入。