88

I have created users 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.

thebossman
  • 4,318
  • 10
  • 32
  • 45
  • 1
    What is the error message you got? – zs2020 Apr 11 '10 at 23:21
  • The test case fails on the line, 'self.assertTrue(login)'; the login() function returns False. – thebossman Apr 12 '10 at 00:27
  • 1
    I basically copied&pasted your 2nd variation and it works on Django 1.3. Can you post the entire code including the imports? – Liorsion Jan 25 '11 at 16:25
  • This has been buried somewhere in a code base I no longer access. If I come across the problem I'll be sure to follow-up, but for the record, it was with an earlier version of Django; I think 1.0.2. – thebossman Jan 27 '11 at 09:32

6 Answers6

132

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')
Pedro M Duarte
  • 20,975
  • 5
  • 37
  • 43
58

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])
approxiblue
  • 6,624
  • 16
  • 47
  • 56
WeizhongTu
  • 5,086
  • 2
  • 31
  • 47
5

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.

Muthuvel
  • 458
  • 6
  • 13
5

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

Chris Adams
  • 4,786
  • 27
  • 28
e-satis
  • 515,820
  • 103
  • 283
  • 322
  • 2
    +1 for this. Even with `django.contrib.sessions.middleware.SessionMiddleware` in middleware classses you still can not login via django.test.Client. It takes me a week to find this answer – pupil Apr 07 '16 at 05:29
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)
-4

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)

Arindam Roychowdhury
  • 3,975
  • 5
  • 43
  • 52
  • 4
    This just worked........... self.user = User.objects.create(username='testuser', password='12345', is_active=True, is_staff=True, 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) – Arindam Roychowdhury Nov 14 '12 at 12:08
  • This has nothing to do with `is_staff` which defines wheter access to the admin panel in general is granted. As you can see the data in the initial posting already has `is_active = 1` and that's also the default for `User.objects.create()`. – jnns Nov 14 '13 at 09:46
  • 1
    @arindamroychowdhury - Wow, that actually worked.. (Your comment, that is) – Richard de Wit Jun 19 '14 at 07:20
  • 1
    It might be a version issue, but I had to comment out your authenticate call. Other than that, your comment worked like a champ! On further testing thought, I found that is_active, is_superuser, and is_staff were all unnecessary. The thing that did it was the call to set_password. – dolphus333 Apr 29 '16 at 13:51