Django认证测试隔离异常:执行登录测试后用户仍保持认证状态
问题分析与解决方案
你的测试失败根源是完全误解了Django中is_authenticated属性的作用:
- 数据库中的
User模型实例,is_authenticated属性永远返回True(这是Django内置属性,用来区分AnonymousUser和实际用户对象),和用户是否在当前会话中登录没有任何关系。 - 你要判断的是「当前测试会话中的用户是否已登录」,应该检查测试客户端(
Client)维护的会话状态,而不是去查数据库里的User实例。
修正后的测试代码
from django.test import TestCase from app.users.models import User class TestLogin(TestCase): def setUp(self): super().setUp() self.email = 'test@test.com' self.password = 'SomeRandomPass96' self.user = User.objects.create_user(email=self.email, password=self.password) # TestCase已自动提供self.client,无需手动实例化 def test_not_authenticated(self): # 检查客户端初始状态为匿名用户 assert not self.client.user.is_authenticated # 或验证会话中无认证用户ID assert '_auth_user_id' not in self.client.session def test_login_success(self): response = self.client.post( '/users/login/', {'email': self.email, 'password': self.password} ) # 登录成功通常会跳转,先断言响应状态码 assert response.status_code in (302, 200) # 检查客户端会话已完成认证 assert self.client.user.is_authenticated # 验证会话中的用户ID与创建的用户匹配 assert self.client.session.get('_auth_user_id') == str(self.user.pk) def test_login_wrong_credentials(self): response = self.client.post( '/users/login/', {'email': self.email, 'password': 'wrongPassword123'} ) # 登录失败通常停在登录页,断言响应状态码 assert response.status_code in (200, 302) # 检查客户端仍处于未认证状态 assert not self.client.user.is_authenticated # 确认会话中无认证用户ID assert '_auth_user_id' not in self.client.session
额外优化点
- 无需手动清理用户数据:Django的
TestCase会为每个测试方法创建独立数据库事务,测试结束后自动回滚,tearDown里的用户删除代码完全多余,可直接移除。 - 无需手动实例化Client:
TestCase基类已在setUp中自动创建self.client实例,你手动赋值的操作属于重复工作,可删除。
内容的提问来源于stack exchange,提问作者Gonzalo Dambra
相关产品推荐
相关产品推荐

