切换日光/暗黑模式
070. 测试环境适配、公共工具与拦截器
学习目标
这一节继续完善测试和基础工具。
学完后,你应该能理解:
- 如何判断当前代码是否运行在 PyTest 环境;
- Redis 工具类为什么要区分测试和生产;
- 覆盖率报告怎么看;
- 用 Agent 生成测试时为什么仍要人工校验;
- 认证中间件和公共函数如何为通用模块做准备。
判断测试环境
项目里需要一个函数判断当前是否在自动化测试环境。
一种简单方式是检查:
py
sys.modules如果里面已经加载了 pytest,就说明当前进程大概率由 PyTest 启动。
这个判断可以用来切换少量测试专用逻辑。
例如 Redis 连接处理。
Redis 测试适配
正式服务运行时,Redis 工具类可以复用连接池。
测试运行时,每个异步用例可能有自己的事件循环。
如果继续复用绑定旧事件循环的连接池,后面可能出现连接失效或事件循环关闭的问题。
所以 Redis 工具类可以这样处理:
- 非测试环境使用连接池;
- 测试环境创建独立客户端;
- 使用结束后关闭客户端连接。
这样测试更稳定。
也不影响正式服务的性能策略。
覆盖率报告
跑完整测试后,会生成覆盖率报告。
报告会告诉你:
- 总覆盖率;
- 每个文件的覆盖率;
- 哪些行没有跑到;
- 哪些分支缺少测试。
例如某个文件覆盖率是 92%,点进去可以看到剩下 8% 是哪些行。
这能指导后续补测试,而不是凭感觉补。
用 Agent 生成测试
可以让 Agent 帮忙生成测试用例。
但生成结果不能直接信。
它可能:
- 读错项目结构;
- 写错导入路径;
- 断言字段不对;
- 忽略缓存或数据库状态;
- 生成很长但无效的代码。
所以更合理的方式是让它先写初稿,再由开发者运行、删改、补断言。
测试最终要以运行结果和业务语义为准。
测试用例命名
PyTest 里函数名不能重复。
如果两个测试函数同名,后面的可能覆盖前面的。
测试文件、测试函数都要有清晰命名。
例如:
py
def test_user_cache_gets_lisi():
...
def test_user_cache_gets_zhangsan():
...这样报告里也更容易定位失败点。
AGENTS.md 的作用
AGENTS.md 可以放项目级说明。
Agent 工具处理项目时,会优先读取这类说明。
适合写:
- 测试要求;
- 代码风格;
- 目录约定;
- 模块边界;
- 生成测试时必须遵守的规则。
也可以在具体模块下放更细的说明文件。
例如 Redis 模块有自己的开发说明,通用模块也有自己的开发说明。
这样 Agent 在处理特定模块时能拿到更准确的上下文。
认证中间件补充
认证中间件需要区分 Token 类型。
例如 API 路由应该要求 API Token。
普通登录接口应该要求访问 Token。
如果不区分,可能出现用错 Token 类型也能访问接口的问题。
这类逻辑适合放在中间件里统一处理,而不是每个接口单独判断。
call 公共函数
通用模块会支持类似拦截器的能力。
例如新增前、新增后、更新后执行某个函数。
这些函数接收的参数不一定完全一样。
有的只需要 row。
有的需要 row 和 session。
有的还需要 user。
call 公共函数的作用是:
- 读取目标函数签名;
- 从上下文里挑出它需要的参数;
- 多余参数不传;
- 如果是异步函数就
await; - 如果是同步函数就直接执行。
这能让拦截器写法更灵活。
雪花 ID 与路径拼接
项目还补充了几个基础工具。
雪花 ID 用来生成纯数字 ID。
它不依赖数据库函数,适合某些需要数字编号的场景。
路径拼接工具要处理:
- 多余斜杠;
- 末尾斜杠;
http和https开头的地址;- 普通相对路径。
这些工具看起来小,但会被通用模块反复调用。
BasicSchema
BasicModel 面向数据库表实体。
它包含 ID、创建时间、更新时间等字段。
但有些请求参数或响应参数不直接参与数据库增删改查。
这类结构更适合继承 BasicSchema。
命名上可以这样区分:
Model表示数据库实体;Schema表示请求或响应结构。
这个区分能减少后续类型混乱。
这一节的重点
这一节是在给通用模块铺底层能力。
你需要记住:
- 测试环境和正式环境可以有少量基础设施差异;
- Redis 连接池要注意事件循环生命周期;
- Agent 生成测试后必须运行和校验;
- Token 类型应该在中间件统一校验;
call函数让同步和异步拦截器共用一套执行方式;Model和Schema要按是否参与数据库实体来区分。