Pytest异步测试覆盖率误报代码行未命中问题排查
pytest异步用例实际执行但覆盖率漏统计的常见原因
代码逻辑实际跑通、断点能走到对应行,但覆盖率报告标记未覆盖,本质是覆盖率工具的追踪钩子没有正确捕获到对应代码行的执行事件,和业务逻辑正确性无关,常见触发原因按排查优先级排序如下:
- 首先排查代码版本与缓存不一致问题:你贴出的测试代码里断言行写的是
assert res[0].number = 0.35,单等号是赋值操作,在assert语句里会直接触发语法错误,如果测试实际能运行通过,说明你执行测试用的代码、和覆盖率工具做字节码插桩用的代码不是同一个版本。先手动删除项目下所有__pycache__目录、.pyc后缀缓存文件,卸载重装本地项目依赖,全量重新执行用例生成覆盖率报告,先排除缓存导致的统计偏差。 - 第二排查覆盖率工具的异步兼容配置缺失:默认配置下的coverage.py对Python async/await语法、尤其是嵌套异步上下文管理器(比如你代码里的
async with session.begin())的行号追踪存在兼容缺陷,会出现上下文块内部代码执行了但没被标记覆盖的问题。需要在coverage配置文件(.coveragerc或者pyproject.toml里的coverage段)添加配置concurrency = ["asyncio"],如果项目同时用到多线程、gevent等其他并发模型,需要把对应并发模式也加到这个配置列表里。 - 第三排查ORM/第三方库C扩展的追踪屏蔽问题:你用到的SQLAlchemy异步Session、ORM实体的动态属性赋值逻辑,默认会用C实现的加速扩展运行,这部分代码执行时不会触发Python层的追踪钩子,会导致coverage漏记。可以在coverage配置里开启C扩展追踪选项,或者临时设置环境变量
DISABLE_SQLALCHEMY_CEXT=1关闭C加速,重跑覆盖率验证是否是该问题。 - 最后排查采集范围与Mock拦截问题:如果测试中对
update_pydantic_object方法、或者方法内部依赖的session.commit/get_pydantic_object做过mock/patch替换,coverage默认不会统计被Mock替换掉的逻辑;另外要确认coverage的source配置包含了被测代码所在的目录,没有把对应文件排除在统计范围外。
快速验证技巧:可以在被标记为未覆盖的代码行加一行抛出固定异常的测试代码,重跑用例如果用例正常通过没有抛异常,就说明确实是覆盖率追踪的配置问题,不是代码没执行到。
内容的提问来源于stack exchange,提问作者Big Guy
相关产品推荐
相关产品推荐

