pytest-recording 是基于 vcrpy 的 pytest 插件,通过序列化请求/响应为 yaml cassette 实现稳定回放;默认 record_mode="once" 导致响应变更时 cassette 不更新,需手动指定模式或删除文件重录。

直接说结论:pytest-recording 本质是基于 vcrpy 的 pytest 插件,它不“录制”真实请求,而是把请求/响应对序列化成 YAML 文件(cassette),后续测试直接读取该文件回放——因此网络不可用、接口限流、数据变动都不会影响测试稳定性。
为什么测试里 HTTP 请求总在变,而 cassette 却没更新?
这是最常见误操作:pytest-recording 默认使用 record_mode="once",即只在 cassette 文件不存在时录制一次,之后全走回放。一旦接口响应结构变更(比如新增字段、状态码调整),测试会因断言失败或解析异常中断,但 cassette 不会自动重录。
- 强制重录所有 cassette:加参数
--record-mode=all或--record-mode=new_episodes - 只重录某一个测试的 cassette:删掉对应
tests/cassettes/xxx.yaml文件再跑 - 检查当前生效的 record mode:在测试函数里打印
vcr.record_mode(需通过 fixture 注入) - 注意:CI 环境应固定为
none,避免意外写入 cassette
如何让不同环境(dev/staging/prod)共用同一组 cassette?
cassette 文件硬编码了请求 URL 和 Host,直接切换 base_url 会导致匹配失败。关键不是改 URL,而是统一「请求指纹」。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
- 用
vcr.filter_sensitive_data抹掉动态部分(如 token、user_id):vcr = VCR(filter_headers=[("Authorization", "XXXX")], filter_query_parameters=["api_key"], before_record_request=remove_dynamic_params) - 在 pytest 配置中通过
vcr_configfixture 统一设置ignore_hosts或match_on(推荐只匹配 method + path + body) - 避免在 cassette 中保留完整域名:用
vcr.register_matcher("host_agnostic", host_agnostic_matcher)自定义 matcher
mock.patch 和 pytest-recording 能一起用吗?优先级怎么定?
能一起用,但顺序很重要:pytest-recording 的 cassette 拦截发生在 requests 库底层(requests.adapters.HTTPAdapter.send),而 mock.patch 如果打在更高层(如业务函数内调用的 api_client.get()),就根本不会触发录制。
- 要录制真实 HTTP 流量 → patch 必须在 requests 层以下,例如:
@patch("requests.Session.request") - 如果只是想跳过网络但保留 cassette 校验逻辑 → 直接用
vcr.use_cassette,别 patch - 混用时注意:mock 会绕过 vcr 的 request/response 记录,导致 cassette 空或不一致
- 调试技巧:启用
vcr.log_level = logging.DEBUG查看是否命中 cassette
真正难的不是怎么录,而是怎么设计 cassette 的生命周期——什么时候该删、哪些字段必须过滤、match_on 规则是否覆盖了所有边界 case。这些细节不写进测试代码里,就只能靠团队约定,而约定最容易被忽略。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










