Skip to content

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 的识别和导入。

AI Agent 课程学习文档。