I have created us开发者_JAVA百科ers for my unit tests in two ways:
1) Create a fixture for "auth.user" that looks roughly like this:
{
"pk": 1,
"model": "auth.user",
"fields": {
"username": "homer",
"is_active": 1,
"password":
"sha1$72cd3$4935449e2cd7efb8b3723fb9958fe3bb100a30f2",
...
}
}
I've left out the seemingly unimportant parts.
2) Use 'create_user' in the setUp function (although I'd rather keep everything in my fixtures class):
def setUp(self):
User.objects.create_user('homer', 'ho...@simpson.net', 'simpson')
Note that the password is simpson in both cases.
I've verified that this info is correctly being loaded into the test database time and time again. I can grab the User object using User.objects.get. I can verify the password is correct using 'check_password.' The user is active.
Yet, invariably, self.client.login(username='homer', password='simpson') FAILS. I'm baffled as to why. I think I've read every single Internet discussion pertaining to this. Can anybody help?
The login code in my unit test looks like this:
login = self.client.login(username='homer', password='simpson')
self.assertTrue(login)
Thanks.
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')
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])
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
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.
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.
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 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)
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)
精彩评论