mock.patch 必须作用于被测试代码的导入位置,因为需替换被测模块内部引用的对象而非其定义位置;例如 api_client.py 中 import requests 后调用 requests.get(),应 patch('api_client.requests.get') 而非 'requests.get'。

mock.patch 为什么必须作用于被测试代码的导入位置?
mock 对象生效的关键,是替换「被测试模块里实际调用的那个对象」,而不是它原本定义的位置。比如你的 api_client.py 里写了 import requests,然后调用 requests.get(),那就要在测试文件中对 api_client.requests 打补丁,而不是 requests 模块本身。
常见错误是写成 @patch('requests.get'),结果测试时依然发出真实请求——因为被测代码压根没从全局 requests 名字空间里拿函数,而是从它自己模块作用域里的 requests 引用取的。
正确做法:
- 查清被测函数所在模块(比如
myapp.services.fetch_user) - 确认它内部怎么引用外部依赖(
import requests还是from requests import get) - 按「模块内名字」打补丁:
@patch('myapp.services.requests.get')或@patch('myapp.services.get')
如何让 mock 返回不同状态码和 JSON 数据?
Mock 对象的 return_value 可以设为任意对象,但 HTTP mock 通常需要模拟 Response 行为。直接返回字典不行,因为被测代码会调用 .json() 和检查 .status_code。
推荐用 unittest.mock.Mock 手动构造最小响应接口:
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"id": 123, "name": "Alice"}
更稳妥的方式是用 responses 库(需额外安装),但它不属于标准库;若坚持纯 unittest,就别试图 mock 整个 requests.Response 类,只 mock 你真正用到的方法和属性即可。
注意点:
-
.json()是方法,所以必须用return_value设它的返回值,或用side_effect抛异常 - 要模拟 404,设
mock_response.status_code = 404,再确保被测逻辑真会检查这个值 - 避免给 mock 对象加一堆没用的属性,只提供被测代码实际访问的字段
测试异常路径时,该用 side_effect 还是 return_value?
当需要让 mock 在调用时抛出异常(比如网络超时、连接拒绝),必须用 side_effect。设 return_value=Exception("boom") 不会抛出,只会返回那个异常实例。
典型场景:
- 模拟请求失败:
mock_get.side_effect = requests.exceptions.ConnectionError - 模拟 JSON 解析失败:
mock_response.json.side_effect = ValueError("Invalid JSON") - 模拟多次调用不同行为:
side_effect=[response1, response2, requests.Timeout]
容易忽略的是:如果被测函数里对异常做了裸捕获(except:)且没 re-raise,mock 抛异常后测试可能“静默通过”,得检查日志或断言最终返回值是否符合预期。
为什么 patch.object 比 patch 更适合 mock 类方法?
当你要 mock 的是某个类的实例方法(比如 ApiClient.fetch()),用 @patch('myapp.api.ApiClient.fetch') 是可行的,但前提是 ApiClient 在被测模块里是作为类名被引用的。一旦被测代码写的是 client = ApiClient(); client.fetch(),那 patch 类方法就不管用了——因为调用发生在实例上,而 patch 默认替换的是类属性。
这时应该用 patch.object 直接操作实例:
client = ApiClient()
with patch.object(client, 'fetch') as mock_fetch:
mock_fetch.return_value = {"data": "ok"}
result = some_function_that_uses(client)
或者,在测试 setup 阶段就用 patch.object 替换类的实例方法,让它影响所有后续创建的实例(需配合 autospec=True 防止拼写错误)。
关键区别:
-
patch替换模块/类级别的名字绑定 -
patch.object替换指定对象上的属性,更贴近运行时实际调用链 - mock 类方法时,如果不确定调用上下文,优先试
patch.object,它更可靠
mock 的边界永远在「被测代码看到什么」,不在「源码写在哪」。多看一眼被测函数的 import 和调用方式,比背文档更快定位问题。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











