应 patch 被测代码中导入 requests 的模块路径(如 'api_client.requests.get'),而非 'requests.get';用 return_value 或 side_effect 控制响应,注意链式调用需逐层 mock;推荐依赖注入提升可测性。

直接用 patch 替换实际请求函数,比写假服务器更轻量、更可控——但必须确保 patch 的目标位置正确,否则 mock 完全不生效。
mock 对象该 patch 哪里?看导入位置,不是定义位置
很多人 patch 失败,是因为在测试文件里写了 @patch('requests.get'),结果没用。真正要 patch 的是被测代码中「使用 requests.get 的那个模块」里 import 的位置。
比如你的业务代码在 api_client.py 中写了:
import requests
def fetch_user(user_id):
return requests.get(f"https://api.example.com/users/{user_id}").json()
而你在 test_api_client.py 中测试它,那 patch 必须指向 api_client.requests.get,而不是 requests.get:
-
@patch('api_client.requests.get')✅(正确) -
@patch('requests.get')❌(只会影响 test 文件里直接调的 requests.get)
用 return_value 和 side_effect 控制响应行为
静态返回值适合简单场景;需要模拟异常、多次不同响应或动态逻辑时,side_effect 更灵活。
- 模拟成功响应:
mock_get.return_value.json.return_value = {"id": 1, "name": "Alice"} - 模拟 HTTP 错误:
mock_get.side_effect = requests.exceptions.ConnectionError("timeout") - 连续两次调用返回不同结果:
mock_get.side_effect = [Mock(json=Mock(return_value={"status": "ok"})), Mock(json=Mock(return_value={"status": "error"}))]
注意:如果被测函数调用了 .json(),mock 对象必须支持链式调用,所以得设 return_value.json.return_value,不能只设 return_value 为 dict。
依赖注入 + mock 更易测,但别为了测试强行改业务逻辑
如果函数硬编码了 requests.get,就只能靠 patch;但如果它接受一个 client 参数,就能直接传入 mock 对象,更直观也更利于单元隔离。
例如重构为:
def fetch_user(user_id, http_client=requests):
return http_client.get(f"https://api.example.com/users/{user_id}").json()
测试时可直接传入 mock:
mock_client = Mock(); mock_client.get.return_value.json.return_value = {...}fetch_user(123, mock_client)
这种写法避免了 patch 作用域和路径问题,但要注意:默认参数 requests 仍是运行时绑定的,若想彻底解耦,建议用 None 占位再内部 fallback,或用依赖注入框架(如 injector)管理。
真实网络请求未被拦截?检查是否漏了 patch 或用了 httpx/urllib3
mock 不生效的常见原因:
- 被测代码实际用的是
httpx.get或urllib3.PoolManager().request,却只 patch 了requests.get - 用了
requests.Session()实例方法(如session.get()),需 patch 对应实例或类方法,而非模块函数 - 异步代码用了
aiohttp,unittest.mock默认不处理协程,得用AsyncMock(Python 3.8+)或pytest-asyncio配合 - 第三方库(如
fastapi.testclient)内部封装了请求,mock 点可能在更高层(如TestClient.get)
最稳的办法:在被测函数开头加个 print(requests.get),确认你 patch 的确实是那个对象。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











