Django模型类被Mock时无法重定向的问题解决
解决Django测试中Mock模型/表单后重定向失败的问题
我之前也遇到过类似的情况,核心问题在于Mock对象默认不会继承原模型类的get_absolute_url方法,而视图里的redirect(new_list)本质是调用这个方法生成重定向URL。下面分步骤给出具体解决方案:
1. 检查并修正Patch路径(最常见的坑)
首先要确认你Patch的是视图/表单中实际引用的模型/表单对象,而不是原模块中的类。比如:
- 如果你的视图文件
myapp/views.py里是from .models import List,那测试时应该Patchmyapp.views.List,而非myapp.models.List - 同理,表单类的Patch路径也要对应视图中导入的位置
错误的Patch路径会导致Mock没有覆盖到视图实际使用的对象,自然无法配合重定向工作。
2. 给Mock实例添加get_absolute_url方法
当你Patch模型类后,生成的Mock实例默认没有原模型的get_absolute_url方法,需要手动配置:
方法一:直接给Mock实例绑定方法
from django.test import TestCase from unittest.mock import patch, Mock from django.urls import reverse class AddListViewTest(TestCase): @patch('myapp.views.List') # 注意Patch路径是视图中引用的List def test_add_list_redirect(self, mock_list): # 创建Mock实例并配置get_absolute_url mock_instance = mock_list.return_value target_url = reverse('list-detail', kwargs={'pk': 1}) mock_instance.get_absolute_url.return_value = target_url # 发送POST请求 response = self.client.post('/add-list/', data={'name': 'Test List'}) # 断言重定向 self.assertRedirects(response, target_url)
方法二:用spec=True继承原模型的结构
如果想让Mock保留原模型的方法结构,可以在Patch时添加spec=True参数,再针对性配置返回值:
@patch('myapp.views.List', spec=True) def test_add_list_redirect(self, mock_list): mock_instance = mock_list.return_value mock_instance.pk = 1 mock_instance.get_absolute_url.return_value = reverse('list-detail', kwargs={'pk': 1}) # 后续测试逻辑同上
3. 处理表单Save返回的Mock实例
如果视图中通过表单的save()方法获取模型实例,需要确保表单Mock的save()返回的对象也有get_absolute_url:
@patch('myapp.views.ListForm') def test_form_submission_redirect(self, mock_form): # 配置表单Mock mock_form_instance = mock_form.return_value mock_form_instance.is_valid.return_value = True # 创建带get_absolute_url的模型Mock实例 mock_list = Mock() mock_list.get_absolute_url.return_value = '/lists/1/' mock_form_instance.save.return_value = mock_list # 发送请求并断言 response = self.client.post('/add-list/', data={'name': 'Test'}) self.assertRedirects(response, '/lists/1/')
4. 避免过度Mock(可选)
如果你的测试不需要完全Mock模型类,也可以只Mock特定方法(比如save()),保留原模型的get_absolute_url:
@patch('myapp.models.List.save') def test_add_list_minimal_mock(self, mock_save): # 原模型的get_absolute_url仍可正常调用 response = self.client.post('/add-list/', data={'name': 'Test'}) self.assertRedirects(response, reverse('list-detail', kwargs={'pk': 1}))
内容的提问来源于stack exchange,提问作者S.j. Sakib
相关产品推荐
相关产品推荐

