pytest-recording 不自动录制 http 请求,因其仅管理 cassette 文件,不拦截流量;录制需显式配置 vcrpy 的 record_mode 并确保其 patch http 客户端。

pytest-recording 本身不录制 HTTP 请求,它只管理已存在的 cassettes(磁带文件),真正的录制依赖 pytest-recorder 或更常见的 vcrpy 集成——但官方推荐搭配 vcrpy 使用,且必须手动配置其录制行为。
为什么 pytest-recording 不会自动录制请求?
pytest-recording 是一个 pytest 插件,职责是:加载、清理、校验 cassette 文件,而不是拦截和录制 HTTP 流量。它默认使用 vcrpy 作为底层录制引擎,但不会自动启用 vcrpy 的录制模式(record_mode),也不会自动 patch requests 或 http.client。
常见错误现象:No cassette found 或测试直接发真实请求并失败(比如网络不通、API 限流、返回非预期数据)。
你需要显式做三件事:
- 安装
vcrpy(pytest-recording不自带它) - 在测试函数或 fixture 中用
@vcr.use_cassette()或vcr.VCR().use_cassette() - 确保
record_mode设置为'once'或'new_episodes'才能生成新 cassette
如何正确配置 vcrpy + pytest-recording 录制第一次请求?
关键点在于让 vcrpy 知道该录什么、存哪、怎么比对。默认 cassette 路径不匹配 pytest-recording 的查找逻辑会导致“找不到磁带”。
实操建议:
- 把 cassette 存放在与测试文件同级的
cassettes/目录下(pytest-recording默认只扫这个路径) - 用
@vcr.use_cassette('test_get_user.yaml', record_mode='once')显式指定文件名和录制策略 - 首次运行前删掉已有 cassette 文件,否则
record_mode='once'会跳过录制 - 确认
vcrpy已 patch 主流 HTTP 客户端:默认支持requests,若用httpx需额外加match_on=['method', 'scheme', 'host', 'port', 'path', 'query', 'body']
示例:
import vcr
import requests
@vcr.use_cassette('cassettes/test_fetch_data.yaml', record_mode='once')
def test_api_call():
resp = requests.get('https://httpbin.org/get?foo=bar')
assert resp.status_code == 200
回放时为什么仍发了真实请求?
最常见原因是 cassette 文件未被加载——不是路径错,就是内容损坏,或是 vcr 实例没共享上下文。
检查项:
- cassette 文件是否真存在于
cassettes/下,且名字和@vcr.use_cassette()中的一致 - 文件是否为空或只有 YAML 头部(说明录制中途失败,比如异常退出没写完)
- 是否误用了多个
vcr.VCR()实例,导致 patch 未生效(推荐全局单例或用装饰器) - 是否在测试中用了未被
vcrpy支持的客户端(如原生urllib.request需手动vcr.install_custom_matchers)
调试技巧:临时加 print(vcr.config) 和 print(vcr._cassettes) 确认加载状态;或设环境变量 VCR_LOG_LEVEL=DEBUG 查日志。
pytest-recording 的 --record-mode 参数到底管什么?
它只控制 pytest-recording 自身对 cassette 的处理策略,**不控制 vcrpy 是否录制**。它的值(none / new_episodes / all)仅影响插件是否允许覆盖已有 cassette、是否跳过校验等,和 HTTP 拦截无关。
真正决定是否发真实请求的,永远是 vcrpy 的 record_mode 和 cassette 是否存在且可读。
容易被忽略的细节:当你用 --record-mode=new_episodes 运行 pytest,这只是告诉插件“允许追加新 interaction”,但如果你的测试里没写 @vcr.use_cassette(..., record_mode='new_episodes'),vcrpy 依然按默认 'once' 行事——不会录。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











