You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何monkeypatch requests库保存测试过程中的请求响应

实现自动录制+Mock请求的方案

你不需要逐个monkeypatch每个系统类实例里的session对象,直接在类层面补丁requests.Session的核心请求方法即可:所有requests.Session实例的get/post/put等上层方法,底层最终都会调用实例的request方法,在类层面打补丁会自动覆盖所有已创建、后续新创建的session实例,不管这些session属于哪个封装类,后续新增多少系统类都不需要额外适配。

具体实现

把下面的fixture放到测试目录的conftest.py中,自动兼容录制、Mock两种模式:

import pytest
import requests
import json
from pathlib import Path
from unittest.mock import patch

# 录制文件存储路径
RECORD_SAVE_PATH = Path("./test_mock_records/request_caches.json")

@pytest.fixture(scope="session", autouse=True)
def auto_record_and_mock():
    # 已存在录制文件时,自动加载规则走Mock模式
    if RECORD_SAVE_PATH.exists():
        import responses
        with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
            with open(RECORD_SAVE_PATH, "r", encoding="utf-8") as f:
                all_records = json.load(f)
            # 批量注册Mock响应
            for record in all_records:
                rsps.add(
                    method=record["method"],
                    url=record["url"],
                    body=record["resp_body"],
                    status=record["resp_status"],
                    headers=record["resp_headers"],
                    match=[responses.matchers.urlencoded_params_matcher(record["req_data"])] if record["req_data"] else []
                )
            yield
        return

    # 无录制文件时走录制模式,拦截请求存真实响应
    request_records = []
    origin_session_request = requests.Session.request

    def wrapped_request(self, method, url, **kwargs):
        # 发送真实请求获取响应
        resp = origin_session_request(self, method, url, **kwargs)
        # 存储请求、响应全量信息
        request_records.append({
            "method": method.upper(),
            "url": url,
            "req_data": kwargs.get("data"),
            "req_json": kwargs.get("json"),
            "resp_status": resp.status_code,
            "resp_headers": dict(resp.headers),
            "resp_body": resp.text
        })
        return resp

    # 全局补丁所有Session实例的request方法
    with patch.object(requests.Session, "request", wrapped_request):
        yield

    # 所有测试执行完成后,保存录制结果到本地
    RECORD_SAVE_PATH.parent.mkdir(exist_ok=True)
    with open(RECORD_SAVE_PATH, "w", encoding="utf-8") as f:
        json.dump(request_records, f, ensure_ascii=False, indent=2)

使用说明

  • 首次录制:删除已存在的录制文件,保证测试环境可以正常访问外部系统,完整执行一次全量测试,执行完成后所有请求、响应数据会自动保存到指定路径
  • 日常测试:只要录制文件存在,fixture会自动通过responses注册所有Mock规则,测试运行全程不会发送真实外部请求,完全不依赖外部服务可用性
  • 接口更新/新增接口时,重复首次录制的流程重新生成录制文件即可,不需要手动维护任何Mock规则

适配调整提示

  • 如果接口存在动态参数(比如时间戳、随机nonce、动态token),可以在加载Mock规则时替换成自定义匹配器,不需要硬匹配全量参数
  • 如果存在文件下载等二进制响应场景,存储时可以把响应体转base64编码,加载Mock时再解码即可
  • fixture加了autouse=True,测试文件里不需要手动引用这个fixture,自动生效

内容的提问来源于stack exchange,提问作者sourcream

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 02:39:09