Django 的 self.client.login(...) 在单元测试中不起作用
Posted
技术标签:
【中文标题】Django 的 self.client.login(...) 在单元测试中不起作用【英文标题】:Django's self.client.login(...) does not work in unit tests 【发布时间】:2011-02-06 19:50:28 【问题描述】:我通过两种方式为我的单元测试创建了用户:
1) 为“auth.user”创建一个大致如下所示的夹具:
"pk": 1,
"model": "auth.user",
"fields":
"username": "homer",
"is_active": 1,
"password":
"sha1$72cd3$4935449e2cd7efb8b3723fb9958fe3bb100a30f2",
...
我省略了看似不重要的部分。
2) 在 setUp 函数中使用“create_user”(虽然我宁愿保留 我的灯具类中的所有内容):
def setUp(self):
User.objects.create_user('homer', 'ho...@simpson.net', 'simpson')
请注意,两种情况下的密码都是 simpson。
我已经一次又一次地验证此信息是否正确加载到测试数据库中。我可以使用 User.objects.get 获取用户对象。我可以使用“check_password”验证密码是否正确。用户处于活动状态。
然而,self.client.login(username='homer', password='simpson') 总是失败。我很困惑为什么。我想我已经阅读了与此相关的每一个 Internet 讨论。有人可以帮忙吗?
我的单元测试中的登录代码如下所示:
login = self.client.login(username='homer', password='simpson')
self.assertTrue(login)
谢谢。
【问题讨论】:
您收到的错误信息是什么? 测试用例失败上线,'self.assertTrue(login)'; login() 函数返回 False。 我基本上复制并粘贴了您的第二个变体,它适用于 Django 1.3。您可以发布包括导入在内的整个代码吗? 这已被埋在我不再访问的代码库中的某个地方。如果我遇到问题,我一定会跟进,但为了记录,这是与早期版本的 Django 相关的;我认为是 1.0.2。 【参考方案1】:不起作用的代码:
from django.contrib.auth.models import User
from django.test import Client
user = User.objects.create(username='testuser', password='12345')
c = Client()
logged_in = c.login(username='testuser', password='12345')
为什么它不起作用?
在上面的 sn-p 中,当创建 User
时,实际的密码哈希设置为 12345
。当客户端调用login
方法时,password
参数的值 12345
会通过哈希函数传递,从而产生类似
hash('12345') = 'adkfh5lkad438....'
然后将其与存储在数据库中的哈希进行比较,客户端被拒绝访问,因为'adkfh5lkad438....' != '12345'
解决方案
正确的做法是调用set_password
函数,它将给定的字符串通过哈希函数并将结果存储在User.password
中。
另外,在调用set_password
之后,我们必须将更新后的User
对象保存到数据库中:
user = User.objects.create(username='testuser')
user.set_password('12345')
user.save()
c = Client()
logged_in = c.login(username='testuser', password='12345')
【讨论】:
你使用User.objects.create_superuser()
和 User.objects.create_user()
来执行这个 set_password()
调用。
当你登录一个人时怎么样
添加到@vdboor 评论:请注意,由于 Django 1.4 还 User.objects.get_or_create()
执行所需的 set_password()
调用【参考方案2】:
更简单的方法是使用 force_login
,这是 Django 1.9 中的新功能。
force_login(user, backend=None)
例如:
class LoginView(TestCase):
def setUp(self):
self.client.force_login(User.objects.get_or_create(username='testuser')[0])
【讨论】:
【参考方案3】:你能像下面这样检查吗,
from django.test import TransactionTestCase, Client
class UserHistoryTest(TransactionTestCase):
self.user = User.objects.create(username='admin', password='pass@123', email='admin@admin.com')
self.client = Client() # May be you have missed this line
def test_history(self):
self.client.login(username=self.user.username, password='pass@123')
# get_history function having login_required decorator
response = self.client.post(reverse('get_history'), 'user_id': self.user.id)
self.assertEqual(response.status_code, 200)
这个测试用例对我有用。
【讨论】:
【参考方案4】:检查 django.contrib.sessions
是否已添加到 INSTALLED_APPS
,因为 client.login()
会检查它是否存在,如果不是,则始终返回 false:
https://docs.djangoproject.com/es/1.9/topics/http/sessions/#enabling-sessions
【讨论】:
为此 +1。即使在中间件类中使用django.contrib.sessions.middleware.SessionMiddleware
,您仍然无法通过 django.test.Client 登录。我花了一个星期才找到这个答案【参考方案5】:
from django.test import TestCase
from django.contrib.auth.models import User
from django.test import Client
class MyProfile(TestCase):
@classmethod
def setUpClass(self):
self.username = 'dummy' + data + '@gmail.com'
self.password = 'Dummy@123'
user = User.objects.create(username=self.username)
user.set_password(self.password)
user.save()
c = Client()
self.client_object = c.login(username=self.username, password=self.password)
self.content_type = "application/json"
response = self.client_object.post('/api/my-profile/', content_type=self.content_type)
【讨论】:
【参考方案6】:如果还有人关注这个,我认为属性 'is_staff' 和 'is_active' 应该保持 True 才能成功登录......
self.user = User.objects.create(username='testuser',password='pwd',is_active=1,is_staff=1)
【讨论】:
这只是工作...... self.user = User.objects.create(username='testuser', password='12345', is_active=True, is_staff=是的,is_superuser=True) self.user.set_password('hello') self.user.save() user = authenticate(username='testuser', password='hello') login = self.c.login(username=' testuser', password='hello') self.assertTrue(login) 这与is_staff
无关,is_staff
通常定义是否授予对管理面板的访问权限。如您所见,初始发布中的数据已经有is_active = 1
,这也是User.objects.create()
的默认值。
@arindamroychowdhury - 哇,这确实有效..(你的评论,就是)
这可能是版本问题,但我不得不注释掉您的身份验证调用。除此之外,你的评论就像一个冠军!经过进一步的测试,我发现is_active、is_superuser和is_staff都是不必要的。这样做是调用 set_password。以上是关于Django 的 self.client.login(...) 在单元测试中不起作用的主要内容,如果未能解决你的问题,请参考以下文章