Django 的 self. client.login (...)在单元测试中不起作用

我通过两种方式为我的单元测试创建了用户:

1)为“ auth.user”创建一个大致如下的 fixture:

    {
"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 获取 User 对象。我可以用‘ check _ password’验证密码是否正确。用户已激活。

然而,无一例外地,self. client.login (username = ‘ homer’,password = ‘ simson’)失败了。我不明白为什么。我想我已经读过了每一个与此相关的网络讨论。有人能帮忙吗?

单元测试中的登录代码如下所示:

    login = self.client.login(username='homer', password='simpson')
self.assertTrue(login)

谢谢。

60144 次浏览

If anyone still following this , I think the attributes 'is_staff' and 'is_active' should be kept True for successfully logging in......

self.user = User.objects.create(username='testuser',password='pwd',is_active=1,is_staff=1)

Can you check like below,

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)

This test case worked for me.

The code that doesn't work:

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')

Why doesn't it work?

In the snippet above, when the User is created the actual password hash is set to be 12345. When the client calls the login method, the value of the password argument, 12345, is passed through the hash function, resulting in something like

hash('12345') = 'adkfh5lkad438....'

This is then compared to the hash stored in the database, and the client is denied access because 'adkfh5lkad438....' != '12345'

The Solution

The proper thing to do is call the set_password function, which passes the given string through the hash function and stores the result in User.password.

In addition, after calling set_password we must save the updated User object to the database:

user = User.objects.create(username='testuser')
user.set_password('12345')
user.save()


c = Client()
logged_in = c.login(username='testuser', password='12345')

Check that django.contrib.sessions is added to INSTALLED_APPS because client.login() checks that it is and will always return false if it is not:

https://docs.djangoproject.com/es/1.9/topics/http/sessions/#enabling-sessions

An easier way is to use force_login, new in Django 1.9.

force_login(user, backend=None)

For example:

class LoginView(TestCase):
def setUp(self):
self.client.force_login(User.objects.get_or_create(username='testuser')[0])
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)

If you are using rest_framework, make sure session-based authentication is enabled. That was my issue.

Go to your settings.py file and check that REST_FRAMEWORK -> DEFAULT_AUTHENTICATION_CLASSES includes SessionAuthentication:

REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.TokenAuthentication",
"rest_framework.authentication.SessionAuthentication",
],
...
}

It looks like the login method uses the vanilla Django session-based approach, so if you were only using rest_framework's token auth that's going to fail.

If you just need to have an authenticated user during testing the test cases you can use force_login which does not need any authentication properties just pass the user object.

    def test_something_view(self):
client = Client()
client.force_login(self.user)
response = client.post(reverse('your custom url'), follow=True)
self.assertEqual(response.status_code, 200)