直接 mock 第三方 SDK 请求方法最可控,但需 patch 其实际发起 HTTP 调用的底层函数(如 session.send),而非仅 requests.get,因 SDK 常封装 Session、重试、自定义 adapter 等,盲目 patch 顶层函数会导致 mock 失效、异常模拟失真、参数校验缺失及响应构造困难;推荐优先使用 requests_mock 拦截 urllib3 层,行为真实且不侵入代码;若 SDK 基于 httpx 或 aiohttp,则须改用对应 Mock 工具;patch 路径必须匹配被测代码中导入的位置,且须覆盖 4xx/5xx、网络异常、JSON 解析错误三类异常路径。

直接 mock 第三方 SDK 的请求方法最可控,但必须 patch 它实际发起 HTTP 调用的那个函数,而不是盲目 patch requests.get。
为什么不能只 patch requests.get
很多 SDK 内部并不直接调用 requests.get,而是封装了 Session、自定义 adapter、重试逻辑或中间件。只 patch 顶层函数会导致:
- mock 失效:SDK 走
session.post()或session.send()时完全绕过你的 patch - 无法模拟真实异常:比如连接超时(
requests.exceptions.Timeout)、重定向循环、SSL 错误——这些都发生在底层 socket 或 urllib3 层 - 参数校验缺失:你 mock 的
requests.get不知道 URL 是否拼错、query 是否漏传、headers 是否缺失 - 状态码和 headers 硬编码困难:返回值需手动构造
Mock(status_code=401, headers={...}),易出错且不可复用
推荐方案:优先用 requests_mock 拦截 HTTP 层
它在 urllib3 底层拦截请求,行为与真实网络一致,且不侵入 SDK 代码。
- 安装:
pip install requests-mock - 在
conftest.py中注册 fixture:import pytest import requests_mock @pytest.fixture def reqmock(): with requests_mock.Mocker() as m: yield m - 测试中精准匹配:
def test_sdk_create_order(reqmock): reqmock.post("https://api.pay.example.com/v2/orders", json={"order_id": "ord_123"}, status_code=201, headers={"X-Request-ID": "abc"}) result = pay_sdk.create_order(amount=99.9) assert result["order_id"] == "ord_123" - 支持 query string 校验:
reqmock.get(url, complete_qs=True),避免因参数顺序不同导致 mock 不命中 - 可设延迟:
reqmock.get(url, json={}, real_http=False, status_code=200, text="ok", headers={}, additional_matcher=...),但更推荐用delay=0.5参数
当 SDK 不用 requests 时,得换工具或改 patch 目标
如果 SDK 基于 httpx 或 aiohttp,requests_mock 完全无效。
立即学习“Python免费学习笔记(深入)”;
-
httpx用户:用httpx.MockTransport,注意它要求显式传入transport实例,不能靠全局 patch -
aiohttp用户:用aioresponses,语法类似requests_mock,但需配合async def测试函数 - 不确定 SDK 底层?用
lsof -i(Linux/macOS)或 Wireshark 抓包看真实发出的请求;或临时加import logging; logging.basicConfig(level=logging.DEBUG)查日志 - 实在找不到调用点?在 SDK 源码里搜
.get(、.post(、.request(、send(、_make_request,重点看它 import 了什么 HTTP 客户端
patch 路径写错是最高频失败原因
mock 的路径必须是「被测试代码导入的位置」,不是函数定义的位置。
- 错误示例:
mocker.patch("sdk_module._make_request")—— 如果你的测试文件是test_sdk.py,而它 import 的是from myapp.sdk import MyClient,那真正要 patch 的是"myapp.sdk.MyClient._make_request"或"myapp.sdk._make_request"(取决于 import 方式) - 验证方式:在测试函数开头加
print(MyClient._make_request),看输出是不是<bound method ...></bound>还是<magicmock ...></magicmock> - 动态代理场景(如用
getattr(client, method)):mock 整个 client 实例比 mock 单个方法更稳,mocker.patch("myapp.sdk.MyClient", return_value=mock_client) - 返回值别用裸 dict:设
return_value=Mock(json=Mock(return_value={"ok": True})),否则调用.json()会报AttributeError
最常被忽略的是异常路径覆盖——不是 mock 一个成功响应就完事,status_code=401、side_effect=requests.exceptions.ConnectionError、json.decoder.JSONDecodeError 这三类必须各写一个测试用例,否则 SDK 的错误处理逻辑永远没被验证过。


















