django单元测试核心是隔离验证models、managers、forms及自定义业务方法,必须用testcase保障数据库操作可回滚;modeladmin配置、url路由、纯模板逻辑不需测;95%场景用testcase,仅事务边界行为才用transactiontestcase;外部依赖须mock,setuptestdata比setup更高效。

直接说结论:Django 单元测试的核心不是“写满覆盖率”,而是针对 models、managers、forms 和自定义业务方法(比如 order.calculate_total())做隔离验证,用 TestCase 而非 SimpleTestCase 保证数据库操作可回滚。
哪些代码必须写测试?看这四类
不值得测的:Django 自带的 ModelAdmin 配置、URL 路由(除非用了复杂正则)、纯模板逻辑。真正要盯住的是:
-
models.py里的字段约束、clean()方法、自定义save()行为 -
managers.py中重写的get_queryset(),比如ActiveOrderManager过滤逻辑 -
forms.py的clean_amount()或clean()全局校验(如“结束时间不能早于开始时间”) - 独立封装的业务函数,例如
utils.py里的apply_discount(cart_items, coupon)
用 TestCase 还是 TransactionTestCase?
95% 场景用 TestCase —— 它在每个测试方法前后用事务 ROLLBACK,快且干净。只有当你明确需要测试事务边界行为(比如并发下单、select_for_update()),才升到 TransactionTestCase,但它会清空数据库再重建表结构,极慢。
常见误用:TransactionTestCase 被用来“解决测试间数据残留”,其实是没调用 super().setUp() 或误改了 setUpTestData() 导致 fixture 污染。
怎么模拟外部依赖?别动 patch 就写不好测试
测试重点是业务逻辑本身,不是第三方 API 是否在线。所有外调必须 mock:
- 发邮件?mock
send_mail:from unittest.mock import patch<br>class OrderTest(TestCase):<br> @patch('myapp.tasks.send_confirmation_email.delay')<br> def test_order_creates_email_task(self, mock_delay):<br> order = Order.objects.create(...)<br> self.assertTrue(mock_delay.called) - 调支付网关?mock 具体客户端实例,而不是模块顶层 —— 否则容易 patch 错位置(比如 patch
'requests.post'太宽,应 patch'payments.gateways.StripeClient.charge') - 读取配置?用
@override_settings(DEBUG=True)替代硬编码,避免污染全局设置
为什么 setUpTestData 比 setUp 更关键?
setUpTestData 在整个测试类初始化时只运行一次,数据插入数据库但被事务保护,后续每个测试方法都可安全读取;而 setUp 每次都新建对象,慢且可能触发重复信号(比如 post_save)。但注意:setUpTestData 里不能修改模型实例字段(因为是共享的),也不能依赖它返回的 QuerySet 做后续 save —— 那些操作得挪到各测试方法里。
一个容易忽略的细节:setUpTestData 创建的对象 ID 在不同测试中是固定的(比如第一个 User 总是 id=1),如果业务逻辑里写了 if user.id == 1 这种硬判断,测试就会假阳性。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











