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(...) 在单元测试中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

django的文档

Django 大神带你飞系列~走进Django

Django:启动django

django的单元测试怎么用

django-admin 和django-admin.py的区别

mac电脑安装django ,运行django报错解决