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

如何测试不同参数值下的Django自定义装饰器?

解决方法

针对你的需求,有几种简单的方式可以测试raise_exception=False的场景,下面逐一说明:

方式1:直接在测试中重新包装原始视图

视图被装饰后,原始的未装饰函数会被保存在__wrapped__属性里(因为用了@wraps),你可以取出它,用raise_exception=False重新装饰,然后直接测试这个新视图:

def test_my_view_redirects_ungrouped_users(self):
    from my_app.views import my_view
    # 获取装饰前的原始视图函数
    original_view = my_view.__wrapped__
    # 用raise_exception=False重新装饰
    test_view = new_group_required("special_group", raise_exception=False)(original_view)

    # 使用RequestFactory调用视图
    from django.test import RequestFactory
    factory = RequestFactory()
    request = factory.get("/my_app/my_view/")
    request.user = self.user_without_group

    response = test_view(request)
    # 验证重定向状态码和目标地址
    self.assertEqual(response.status_code, 302)
    self.assertRedirects(response, f"{settings.LOGIN_URL}?next=/my_app/my_view/")

如果想用Client而不是RequestFactory,可以临时挂载测试视图到URL配置中:

def test_my_view_redirects_ungrouped_users(self):
    from my_app.views import my_view
    original_view = my_view.__wrapped__
    test_view = new_group_required("special_group", raise_exception=False)(original_view)

    # 临时创建URL配置
    from django.urls import path
    temp_urlconf = type('TempURLs', (), {
        'urlpatterns': [path("my_app/my_view/", test_view)]
    })

    with self.settings(ROOT_URLCONF=temp_urlconf):
        self.client.force_login(user=self.user_without_group)
        response = self.client.get("/my_app/my_view/")
        self.assertRedirects(response, f"{settings.LOGIN_URL}?next=/my_app/my_view/")

方式2:用Mock替换装饰器(适合复杂场景)

如果需要保留原视图的导入逻辑,可以用unittest.mock替换new_group_required,强制它返回raise_exception=False的装饰器:

from unittest.mock import patch

def test_my_view_redirects_ungrouped_users(self):
    from my_app.decorators import new_group_required

    # 定义mock装饰器,忽略传入的raise_exception,强制设为False
    def mock_decorator(group, login_url=None, raise_exception=True):
        return new_group_required(group, login_url=login_url, raise_exception=False)

    # 在导入视图前patch装饰器,确保视图使用mock版本
    with patch('my_app.views.new_group_required', side_effect=mock_decorator):
        from my_app.views import my_view
        from django.test import RequestFactory

        factory = RequestFactory()
        request = factory.get("/my_app/my_view/")
        request.user = self.user_without_group

        response = my_view(request)
        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, f"{settings.LOGIN_URL}?next=/my_app/my_view/")

方式3:单独测试装饰器逻辑

你也可以直接测试new_group_required的核心逻辑,验证不同参数下的行为:

def test_new_group_required_behavior(self):
    from my_app.decorators import new_group_required
    from django.core.exceptions import PermissionDenied

    # 测试raise_exception=False时,无权限用户返回False
    check_func = new_group_required("special_group", raise_exception=False).test_func
    self.assertFalse(check_func(self.user_without_group))

    # 测试raise_exception=True时,无权限用户抛出PermissionDenied
    check_func_exception = new_group_required("special_group", raise_exception=True).test_func
    with self.assertRaises(PermissionDenied):
        check_func_exception(self.user_without_group)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 00:01:40