patch需在测试函数参数接收mock对象,因其仅在当前作用域生效且必须显式传入才能调用或断言;漏写会导致真实函数执行,如requests.get发出实际请求而引发ConnectionError或断言失败。

为什么 patch 要在测试函数参数里接收 mock 对象
因为 patch 装饰器注入的 mock 不是全局变量,它只在当前测试函数作用域内生效,且必须显式接收才能调用或断言。漏写参数会导致真实函数被调用,测试失效。
常见错误现象:requests.get 实际发出了 HTTP 请求,报错 ConnectionError 或返回真实响应,断言失败。
- 用
@patch('requests.get')时,测试函数签名必须带一个形参,比如mock_get - mock 对象默认返回空
Mock实例,需手动设置return_value或side_effect - 路径要写对:patch 的字符串是「被测试代码里 import 的位置」,不是源文件位置。例如你在
views.py写了import requests,就 patch'requests.get';如果写了from requests import get,就得 patch'views.get'
如何让 mock 返回带 status_code 和 json() 的响应对象
Django 视图里常这样用:resp = requests.get(url); resp.json(); resp.status_code。直接 mock requests.get 返回一个普通 dict 不行——它没有 json() 方法。
正确做法是构造一个具备行为的 mock 响应对象:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
mock_resp = Mock()
mock_resp.status_code = 200
mock_resp.json.return_value = {'id': 123, 'name': 'test'}
mock_get.return_value = mock_resp
- 别用
return_value={'status_code': 200}—— 这只是个 dict,没方法 - 一定要链式设置
.json.return_value,而不是.json = lambda: {...},否则断言mock_resp.json.assert_called()会失败 - 如果要模拟异常(如超时),用
side_effect = requests.Timeout,不是return_value = Exception
测试中调用了多个外部服务,怎么避免 patch 写满一页
一个视图可能同时调 requests.get、boto3.client、第三方 SDK 的方法。全用 @patch 装饰器嵌套会让测试函数参数变长,可读性差,也容易顺序错乱。
- 优先用上下文管理器
with patch(...),只在需要的地方 patch,作用域清晰 - 把常用 mock 响应逻辑抽成 fixture(pytest)或 setUp 方法(unittest),但注意不要跨测试共享 state
- 对同一模块多个函数,可以 patch 整个模块:
@patch('myapp.utils.requests'),然后通过mock_requests.get、mock_requests.post分别控制 - 避免 patch 模块顶层导入,比如
@patch('requests')后又写from requests import get—— 此时 patch 失效,因为实际调用的是本地引用的get
Django TestCase 里用 mock 为什么数据库事务不回滚
TestCase 默认每个测试用事务包裹并自动 rollback,但 mock 本身不参与事务。问题出在:如果你在 mock 里手动改了数据库(比如 patch 了一个本该发请求、结果却偷偷 save 了 model 的函数),那数据真会留在测试 DB 里。
- mock 只拦截调用,不接管执行逻辑 —— 如果你 mock 的函数内部有 side_effect 执行了
User.objects.create(),这条记录不会被 rollback - 验证是否污染:测试末尾加
self.assertEqual(User.objects.count(), 0),失败就说明 mock 里混入了真实 DB 操作 - 更安全的做法是,所有 side_effect 中的 DB 操作,改用
factory_boy或内存对象模拟,而非真实 ORM 调用
mock 的边界很窄,它只管“调没调”和“返回啥”,不管被 mock 的函数原本该干啥。越复杂的 side_effect,越容易掩盖真实依赖和副作用。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










