Python单元测试Mock实例方法:Django模型外键方法模拟
Django无数据库单元测试:Mock外键关联返回不同硬编码结果
核心思路
不用数据库的话,别费劲patch整个模型的关联方法,直接给每个Mock实例单独绑定对应的外键Mock对象就行——毕竟你要的是每个实例返回不同结果,针对性赋值比全局patch更靠谱。
假设你的模型结构(对应最小示例)
# models.py from django.db import models class User(models.Model): name = models.CharField(max_length=100) email = models.EmailField() class Order(models.Model): order_number = models.CharField(max_length=20) user = models.ForeignKey(User, on_delete=models.CASCADE)
基础测试写法:直接绑定Mock实例
# tests.py from unittest.mock import Mock from django.test import TestCase from myapp.models import Order, User class OrderTestCase(TestCase): def test_order_user_access(self): # 造两个不同的Mock User,硬编码不同属性值 user_alice = Mock(spec=User) user_alice.name = "Alice" user_alice.email = "alice@example.com" user_bob = Mock(spec=User) user_bob.name = "Bob" user_bob.email = "bob@example.com" # 造两个Order实例,直接把对应的Mock User绑到user属性上 order1 = Mock(spec=Order) order1.order_number = "ORD001" order1.user = user_alice # 跳过数据库查询,直接赋值 order2 = Mock(spec=Order) order2.order_number = "ORD002" order2.user = user_bob # 验证结果 self.assertEqual(order1.user.name, "Alice") self.assertEqual(order1.user.email, "alice@example.com") self.assertEqual(order2.user.name, "Bob") self.assertEqual(order2.user.email, "bob@example.com")
进阶:模拟查询集返回带不同外键的实例
如果需要模拟Order.objects.all()这类查询操作,用@patch拦截模型的objects,再返回你提前造好的带绑定外键的Mock实例:
from unittest.mock import patch class OrderQueryTestCase(TestCase): @patch('myapp.models.Order.objects') def test_order_queryset_with_mocked_users(self, mock_order_objects): # 先造好不同的Mock User user_alice = Mock(spec=User) user_alice.name = "Alice" user_bob = Mock(spec=User) user_bob.name = "Bob" # 造Order实例并绑定对应User order1 = Mock(spec=Order) order1.user = user_alice order2 = Mock(spec=Order) order2.user = user_bob # 让查询集返回这两个订单 mock_order_objects.all.return_value = [order1, order2] # 测试查询逻辑 orders = Order.objects.all() self.assertEqual(orders[0].user.name, "Alice") self.assertEqual(orders[1].user.name, "Bob")
关键注意点
- 用
spec=Model可以让Mock实例只拥有原模型的属性/方法,避免拼写错属性名还查不出来的问题 - 直接赋值外键属性,绕开Django的延迟加载机制,完全不需要数据库连接
- 如果要模拟反向关联(比如
user.orders),给Mock User加个方法就行:user_alice.orders.return_value = [order1]
内容的提问来源于stack exchange,提问作者Phocacius
相关产品推荐
相关产品推荐

