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

测试Django用户与组权限时简单测试用例执行失败

解决Django Guardian权限测试中Permission不存在的问题

问题分析

你遇到的核心问题是测试中手动创建的权限在验证阶段无法被找到,且权限表始终为空,主要由以下原因导致:

  1. 测试用例事务回滚:Django的TestCase默认会将每个测试包裹在事务中,测试结束后自动回滚所有操作,因此setUp中创建的权限在测试外查询时看不到,甚至在测试内部也可能因事务机制导致权限未正确持久化。
  2. 不必要的手动权限创建:Django会自动为注册的模型生成add_<model>、change_<model>、view_<model>、delete_<model>标准权限,手动创建不仅冗余,还可能引发权限匹配冲突。
  3. 用户名不一致:setUp中创建的用户名为user_user,但测试方法中查找的是editor_user,这会导致用户查询失败,后续权限分配也会受影响。

修复步骤

1. 修正代码中的明显错误

统一setUp和测试方法中的用户名,避免用户查询失败。同时移除手动创建权限的代码,改用Django自动生成的权限。

2. 确保测试环境中权限被正确生成

在测试的setUp阶段调用Django的create_permissions方法,强制生成目标模型的权限,避免测试环境中权限未加载的问题。

3. 使用实例变量优化代码

将用户和Reminder实例保存为测试类的实例变量,减少重复数据库查询,提升代码可读性。

修正后的完整测试代码

from django.test import TestCase
from django.contrib.auth.models import Permission
from django.contrib.auth import get_user_model
from guardian.shortcuts import assign_perm
from .models import Reminder
from django.contrib.auth.management import create_permissions
from django.contrib.contenttypes.models import ContentType

class ReminderPermissionsTestCase(TestCase):
    def setUp(self):
        # 生成Reminder所属app的所有模型权限
        content_type = ContentType.objects.get_for_model(Reminder)
        create_permissions(content_type.app_label)
        
        # 创建测试用户(统一用户名)
        self.editor_user = get_user_model().objects.create(username="editor_user")
        
        # 创建Reminder实例
        self.reminder_crud = Reminder.objects.create(
            open=True,
            reminder_date="2023-09-03 12:00:00",
            subject="Reminder with CRUD permissions",
            created_by=self.editor_user,
            reminder_text="This is a reminder with CRUD permissions."
        )

    def test_editor_has_crud_permissions(self):
        # 验证权限已存在(可选,用于调试)
        self.assertTrue(Permission.objects.filter(codename="change_reminder").exists())
        self.assertTrue(Permission.objects.filter(codename="delete_reminder").exists())
        
        # 分配对象级权限
        assign_perm("change_reminder", self.editor_user, self.reminder_crud)
        assign_perm("delete_reminder", self.editor_user, self.reminder_crud)
        
        # 验证权限
        self.assertTrue(self.editor_user.has_perm("change_reminder", self.reminder_crud))
        self.assertTrue(self.editor_user.has_perm("delete_reminder", self.reminder_crud))

额外说明

  • 权限表为空的解释:TestCase的事务回滚机制会在测试结束后撤销所有数据库操作,因此在测试外部查询auth_permission表会看不到测试中生成的权限。若要在测试过程中验证权限存在,需在测试方法内添加查询断言。
  • 确认模型注册:确保Reminder模型所在的app已添加到settings.py的INSTALLED_APPS中,否则Django不会自动为其生成权限。
  • TransactionTestCase替代方案:若需要在测试后保留数据库数据用于调试,可改用TransactionTestCase,它会在每个测试后截断表而非回滚事务,但测试执行速度会稍慢。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 21:13:09