You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:29:52