对django业务逻辑层mock的核心是在调用位置打补丁,而非定义位置;需按import引用路径patch(如views中使用的路径),可用mock.patch.object或side_effect处理多态返回与异常,避免setupclass中patch导致状态污染。

直接回答:对Django业务逻辑层做Mock,核心是「在调用发生的位置打补丁」,而不是在定义位置——否则90%的测试会静默失效。
mock.patch 路径必须匹配 import 时的引用路径
很多人写 @mock.patch("myapp.services.do_something") 却发现没生效,原因往往是:业务代码里实际是 from utils import do_something,然后调用了 do_something()。此时 patch 必须写成 @mock.patch("myapp.views.do_something")(即在 views 模块内被导入并使用的路径),而非函数原始定义路径。
- 查路径最可靠的方式:在业务函数内部加
print(do_something),运行测试看输出里的模块名 - 绝对不要 patch 函数定义所在文件的路径,除非业务代码也是从那里直接 import 的
- 使用
mock.patch.object可绕过路径问题,但只适用于你持有目标对象引用的场景(比如类属性、实例方法)
测试 Django 视图时,优先 patch service 层而非 API 调用
例如视图 order_create 内部调用了 payment_service.charge() 和 inventory_service.reserve()。这时不该 mock requests.post 或 httpx.AsyncClient,而应直接 patch 这两个 service 方法:
调用 Cutout.Pro 视觉处理 API 进行背景移除、人像抠图和照片增强,支持文件上传与图片 URL 输入。
@mock.patch("orders.views.payment_service.charge")
@mock.patch("orders.views.inventory_service.reserve")
def test_order_create_success(self, mock_reserve, mock_charge):
mock_charge.return_value = {"status": "success", "tx_id": "tx_123"}
mock_reserve.return_value = True
response = self.client.post("/api/orders/", data={"item_id": 1})
self.assertEqual(response.status_code, 201)
- 这样能隔离网络、第三方依赖,专注验证业务编排逻辑
- 如果 service 层本身还依赖数据库,用
TestCase自带的事务回滚即可,无需额外 mock model - 若 service 是 class method,用
@mock.patch.object(PaymentService, "charge")更稳定
side_effect 处理多态返回和异常分支
真实业务中一个函数可能根据参数返回不同结构,或抛出不同异常。return_value 不够用,必须用 side_effect:
- 按调用顺序返回值:
mock_func.side_effect = [{"id": 1}, {"id": 2}, ValueError("timeout")] - 根据参数动态响应:
mock_func.side_effect = lambda x: {"result": "ok"} if x > 0 else {"error": "invalid"} - 抛出特定异常触发下游错误处理:
mock_func.side_effect = ConnectionError("down") - 注意:一旦设了
side_effect,return_value就被忽略
容易被忽略的坑:patch 生效范围与 setUpClass 冲突
如果你在 setUpClass 里 patch 了某个函数,它会在所有测试方法间共享状态——比如一个 mock 的 call_count 累加,导致后续测试断言失败。更糟的是,某些 patch 在 setUpClass 中初始化后,无法被单个测试方法内的 with mock.patch(...) 覆盖。
- 原则:patch 尽量放在测试方法内(装饰器或
with语句),避免类级 patch - 如果必须复用,用
setUp而非setUpClass,并在每次测试前重置:mock_func.reset_mock() - Django 的
TestCase默认每个测试方法在独立事务中运行,但 mock 状态不会自动重置——这点和数据库不同,必须手动干预
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










