测试Django用户与组权限时简单测试用例执行失败
解决Django Guardian权限测试中Permission不存在的问题
问题分析
你遇到的核心问题是测试中手动创建的权限在验证阶段无法被找到,且权限表始终为空,主要由以下原因导致:
- 测试用例事务回滚:Django的
TestCase默认会将每个测试包裹在事务中,测试结束后自动回滚所有操作,因此setUp中创建的权限在测试外查询时看不到,甚至在测试内部也可能因事务机制导致权限未正确持久化。 - 不必要的手动权限创建:Django会自动为注册的模型生成
add_<model>、change_<model>、view_<model>、delete_<model>标准权限,手动创建不仅冗余,还可能引发权限匹配冲突。 - 用户名不一致: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
相关产品推荐
相关产品推荐

