pytest-watch 默认不支持热加载,因python模块缓存机制导致修改后仍执行旧代码;推荐使用--import-mode=importlib配合模块卸载,但对patch/mock、复杂依赖或c扩展支持有限。

pytest-watch 默认不支持 Python 代码热加载
它只监听文件变化并重启整个 pytest 进程,但 Python 模块一旦被 import 就缓存在 sys.modules 里,新代码不会自动生效——你改了测试或被测代码,pytest-watch 会重跑,但旧模块还在内存里,结果可能和预期不符。
常见错误现象:AssertionError 没变、断言仍走老逻辑、print 不输出新内容、mock 行为没更新。
- 根本原因不是 pytest-watch 坏了,而是 Python 的模块缓存机制没被清理
- 不能靠删
__pycache__或重启终端解决,得在每次运行前主动卸载模块 - Pytest 插件如
pytest-reload已停更且不兼容较新版本;手动 reload 容易漏模块、触发循环导入
用 pytest --import-mode=importlib 强制按需导入
这是最轻量、官方支持的解法。它让 pytest 在每次收集测试时,用 importlib.import_module() 替代普通 import,配合模块卸载能真正“看到”变更。
使用场景:中小型项目、无跨文件 patch/mocks 依赖、不需要实时调试器介入。
- 必须搭配
--import-mode=importlib启动 pytest(仅 pytest 7.0+ 支持) -
pytest-watch需通过--onchange透传该参数:pytest-watch --onchange "pytest --import-mode=importlib"
- 避免在
conftest.py或测试文件顶部做全局from xxx import yyy,否则导入仍走缓存路径 - 性能影响轻微:每个测试文件多一次
importlib.reload()开销,千级测试下延迟增加约 5–10%
遇到 patch/mock 失效就得手动清理 sys.modules
当测试里用了 unittest.mock.patch(尤其装饰器或上下文管理器形式),即使启用了 importlib 模式,patch 目标模块若早于测试被导入过,依然会 mock 错对象。
典型错误信息:TypeError: cannot patch 'xxx' as it is not a module, class, method, function, traceback, frame or code object,或 mock 完全没生效。
- 在
conftest.py的pytest_runtest_makereport或pytest_sessionstart钩子中,删掉所有已加载的相关模块:import sys<br>for mod in list(sys.modules.keys()):<br> if mod.startswith('myapp.') or mod == 'myapp':<br> del sys.modules[mod] - 注意别删核心模块(如
os、pytest),否则 pytest 自身崩溃 - 如果项目用
fastapi或django,它们的 autoreload 机制和 pytest-watch 冲突,建议关掉开发服务器的热重载,只留 pytest-watch 管测试
复杂项目建议放弃热加载,改用快速冷启动
模块依赖深、动态生成代码、大量 C 扩展(如 numpy、pandas)、或用了 pydantic v2 的模型重建逻辑——这些都会让 reload 行为不可控,强行热加载反而浪费排查时间。
实操建议:
pytest-watch --onchange "killall -q python && pytest -xvs",配合
-x(失败即停)和 -v(详细输出),实际等待时间未必比 reload 更长。
- Pytest 启动本身很快,真正耗时的是测试执行;冷启动只是多花 200–400ms 初始化解释器
- CI/CD 和本地开发应保持一致行为,热加载只是“看起来快”,容易掩盖模块初始化顺序问题
- 真正值得投入的是写好 fixture 作用域、用
tmp_path隔离 IO、减少全局状态——这些比 reload 更影响迭代速度
reload 的边界很窄:它只对纯 Python 模块 + 线性导入链有效。一旦涉及 __init__.py 中的副作用、Cython 编译模块、或第三方库内部缓存,就大概率失效。这时候盯着 reload 日志不如确认测试是否真的覆盖了变更点。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











