如何测试不同参数值下的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
相关产品推荐
相关产品推荐

