Self.client.login (…) Django не працює в модульних тестах


83

Я створив користувачів для своїх модульних тестів двома способами:

1) Створіть прилад для "auth.user", який виглядає приблизно так:

    { 
        "pk": 1, 
        "model": "auth.user", 
        "fields": { 
            "username": "homer", 
            "is_active": 1, 
            "password": 
"sha1$72cd3$4935449e2cd7efb8b3723fb9958fe3bb100a30f2", 
            ... 
        } 
    }

Я залишив, здавалося б, неважливі частини.

2) Використовуйте 'create_user' у функції setUp (хоча я волів би зберегти все у своєму класі світильників):

def setUp(self): 
       User.objects.create_user('homer', 'ho...@simpson.net', 'simpson') 

Зверніть увагу, що в обох випадках паролем є Simpson.

Я переконався, що ця інформація раз за разом правильно завантажується в тестову базу даних. Я можу захопити об'єкт User за допомогою User.objects.get. Я можу перевірити правильність пароля, використовуючи "check_password". Користувач активний.

Проте незмінно self.client.login (ім'я користувача = 'homer', password = 'simpson') ПОМИЛЯЄ. Мене бентежить, чому. Здається, я прочитав кожну окрему дискусію, яка стосується цього. Хто-небудь може допомогти?

Код входу в моєму модульному тесті виглядає так:

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

Дякую.


1
Яке повідомлення про помилку ви отримали?
zs2020,

Тестовий випадок не вдався у рядку, 'self.assertTrue (login)'; функція login () повертає False.
thebossman

1
Я скопіював і вставив вашу другу варіацію, і вона працює на Django 1.3. Чи можете ви розмістити весь код, включаючи імпорт?
Liorsion

Це поховано десь у кодовій основі, до якої я більше не маю доступу. Якщо я зіткнуся з проблемою, я обов'язково продовжуватиму її роботу, але для запису, це було з попередньою версією Django; Думаю, 1.0.2.
thebossman

Відповіді:


120

Код, який не працює:

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

Чому це не працює?

У наведеному вище фрагменті при 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')

44
Ви використовуєте User.objects.create_superuser()та User.objects.create_user()виконуєте саме цей set_password()дзвінок.
vdboor

як щодо того, коли ви ввійдете в систему
скелястий єнот

додати до коментаря @vdboor: зауважте, що оскільки Django 1.4 також User.objects.get_or_create()виконує необхідний set_password()виклик
furins

51

Простіший спосіб - це використання 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])

5

Чи можете ви перевірити, як показано нижче,

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)

Цей тест працював для мене.


5

Перевірте, що django.contrib.sessionsдодано, INSTALLED_APPSтому що client.login()перевіряє, чи є, і завжди поверне false, якщо ні:

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


2
+1 за це. Навіть django.contrib.sessions.middleware.SessionMiddlewareу проміжних класах ви все ще не можете ввійти через django.test.Client. Мені потрібен тиждень, щоб знайти цю відповідь
учень

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)

-3

Якщо хтось все ще дотримується цього, я думаю, що атрибути 'is_staff' та 'is_active' повинні бути збереженими для успішного входу в систему ......

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


4
Це щойно спрацювало ........... 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 (логін)
Arindam Roychowdhury

Це не має нічого спільного з тим, is_staffщо визначає, яким чином надається доступ до адміністративної панелі. Як ви можете бачити, дані в початковій проводці вже є, is_active = 1і це також є типовим для User.objects.create().
jnns

1
@arindamroychowdhury - Ого, це насправді спрацювало .. (Ваш коментар, тобто)
Річард де Віт

1
Можливо, це проблема версії, але мені довелося прокоментувати ваш дзвінок для автентифікації. Окрім цього, ваш коментар працював як чемпіон! Подальше тестування, я виявив, що is_active, is_superuser та is_staff були непотрібними. Все, що це зробило, - це виклик set_password.
dolphus333
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.