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

调用Test时覆盖method_decorator失败,Django测试补丁失效求助

补丁失效原因及解决方案

问题根源

当用@method_decorator(super_admin_login_required, name="dispatch")装饰视图类时,装饰器会在类定义阶段就完成绑定,把权限检查逻辑注入到dispatch方法中。后续用patch替换super_admin_login_required函数时,已经无法影响已经被装饰好的视图类——因为内存中的ClientActivityReport类的dispatch方法早已经是被原装饰器处理过的版本了。

可行解决方案

方案一:直接绕过视图类的装饰后的dispatch方法

直接获取视图类未被装饰的原始dispatch方法,用patch.object替换掉当前类的dispatch,跳过权限检查:

class ClientActivityTestCase(APITestCase):
    def test_client_activity_view_get(self):
        # 从类的原始属性中获取未被装饰的dispatch方法
        original_dispatch = ClientActivityReport.__dict__['dispatch']
        
        with patch.object(ClientActivityReport, 'dispatch', original_dispatch):
            response = self.client.get(
                reverse("client_activity_report"), 
                HTTP_ORIGIN=settings.HOST_NAME, 
                format='json'
            )
            self.assertEqual(response.status_code, status.HTTP_200_OK)
            self.assertIn("Client Activity Report", response.content.decode())

方案二:创建并登录超级管理员用户(更贴近真实业务场景)

直接构造符合权限要求的用户,让权限检查自然通过,不需要修改装饰器:

class ClientActivityTestCase(APITestCase):
    def test_client_activity_view_get(self):
        # 创建满足权限要求的超级管理员用户
        super_admin = User.objects.create_superuser(
            username="test_superadmin",
            email="admin@example.com",
            password="testpass123",
            role="superadmin"  # 确保User模型的role字段对应get_role_display返回"superadmin"
        )
        # 登录该用户
        self.client.login(username="test_superadmin", password="testpass123")
        
        response = self.client.get(
            reverse("client_activity_report"), 
            HTTP_ORIGIN=settings.HOST_NAME, 
            format='json'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn("Client Activity Report", response.content.decode())

方案三:patch权限装饰器依赖的user_passes_test

super_admin_login_required本质是调用user_passes_test生成装饰器,直接patchuser_passes_test让它返回原函数,即可跳过权限检查:

from django.contrib.auth.decorators import user_passes_test

class ClientActivityTestCase(APITestCase):
    def test_client_activity_view_get(self):
        # mock user_passes_test,使其不做任何权限检查直接返回原函数
        def mock_user_passes_test(*args, **kwargs):
            def decorator(func):
                return func
            return decorator
        
        with patch('adminportal.views.user_passes_test', mock_user_passes_test):
            # 重新导入视图类(因为原类已被装饰,需要加载未被装饰的版本)
            from adminportal.views import ClientActivityReport
            
            response = self.client.get(
                reverse("client_activity_report"), 
                HTTP_ORIGIN=settings.HOST_NAME, 
                format='json'
            )
            self.assertEqual(response.status_code, status.HTTP_200_OK)
            self.assertIn("Client Activity Report", response.content.decode())

内容的提问来源于stack exchange,提问作者Yousaf Zahid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:32:26