Django self.client.login (…) не работает в модульных тестах


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 (username = '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

Ответы:


122

Код, который не работает:

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

как насчет того, когда вы зарегистрируете человека в
rocky

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

53

Более простой способ - использовать 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/#enables-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 должны быть сохранены True для успешного входа в систему ...

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 (логин)
Ариндам Ройчоудхури,

Это не имеет ничего общего с тем, 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.