Self.client.login (…) Django nie działa w testach jednostkowych


83

Utworzyłem użytkowników do moich testów jednostkowych na dwa sposoby:

1) Utwórz urządzenie dla „auth.user”, które wygląda mniej więcej tak:

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

Pominąłem pozornie nieistotne części.

2) Użyj 'create_user' w funkcji setUp (chociaż wolałbym zachować wszystko w mojej klasie urządzeń):

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

Zauważ, że hasło to simpson w obu przypadkach.

Sprawdziłem, czy te informacje są poprawnie ładowane do testowej bazy danych raz po raz. Mogę pobrać obiekt użytkownika za pomocą User.objects.get. Mogę sprawdzić, czy hasło jest prawidłowe, używając opcji „check_password”. Użytkownik jest aktywny.

Jednak niezmiennie self.client.login (nazwa użytkownika = 'homer', hasło = 'simpson') FAILS. Jestem zdumiony, dlaczego. Wydaje mi się, że czytałem każdą dyskusję internetową na ten temat. Czy ktoś może pomóc?

Kod logowania w moim teście jednostkowym wygląda następująco:

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

Dzięki.


1
Jaki jest komunikat o błędzie?
zs2020,

Przypadek testowy kończy się niepowodzeniem w wierszu „self.assertTrue (login)”; funkcja login () zwraca False.
thebossman

1
W zasadzie skopiowałem i wkleiłem twoją drugą odmianę i działa na Django 1.3. Czy możesz wysłać cały kod, w tym import?
Liorsion

Zostało to ukryte gdzieś w bazie kodu, do której już nie mam dostępu. Jeśli napotkam problem, na pewno będę kontynuował, ale dla przypomnienia, dotyczyło to wcześniejszej wersji Django; Myślę, że 1.0.2.
thebossman

Odpowiedzi:


122

Kod, który nie działa:

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

Dlaczego to nie działa?

W powyższym fragmencie, gdy Userjest tworzony, aktualny skrót hasła jest ustawiony na 12345. Gdy klient wywołuje loginmetodę, wartość passwordargumentu 12345jest przekazywana przez funkcję skrótu, co daje w wyniku coś podobnego

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

Jest to następnie porównywane z hashem przechowywanym w bazie danych, a klientowi odmawia się dostępu, ponieważ 'adkfh5lkad438....' != '12345'

Rozwiązanie

Właściwą rzeczą do zrobienia jest wywołanie set_passwordfunkcji, która przekazuje podany ciąg przez funkcję skrótu i ​​zapisuje wynik w User.password.

Dodatkowo po wywołaniu set_passwordmusimy zapisać zaktualizowany Userobiekt do bazy danych:

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

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

44
Jesteś pożytkiem User.objects.create_superuser()i User.objects.create_user()wykonujesz dokładnie to set_password()wezwanie.
vdboor

co powiesz na to, że zalogujesz osobę
skalny szop

dodać do komentarza @vdboor: zauważ, że od Django 1.4 również User.objects.get_or_create()wykonuje wymagane set_password()połączenie
furins

53

Łatwiejszym sposobem jest użycie force_login, nowość w Django 1.9.

force_login(user, backend=None)

Na przykład:

class LoginView(TestCase):
    def setUp(self):
        self.client.force_login(User.objects.get_or_create(username='testuser')[0])

5

Czy możesz sprawdzić jak poniżej,

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)

Ten przypadek testowy zadziałał dla mnie.



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

Jeśli ktoś nadal to śledzi, myślę, że atrybuty „is_staff” i „is_active” powinny pozostać True, aby pomyślnie się zalogować ......

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


4
To właśnie zadziałało ........... self.user = User.objects.create (nazwa użytkownika = 'testuser', hasło = '12345', is_active = True, is_staff = True, is_superuser = True) self. user.set_password ('hello') self.user.save () user = authentication (username = 'testuser', password = 'hello') login = self.c.login (username = 'testuser', password = 'hello' ) self.assertTrue (login)
Arindam Roychowdhury

Nie ma to nic wspólnego z is_stafftym, czy ogólnie jest przyznawany dostęp do panelu administratora. Jak widać, dane w początkowej publikacji już mają is_active = 1i jest to również ustawienie domyślne dla User.objects.create().
jnns

1
@arindamroychowdhury - Wow, to faktycznie zadziałało .. (Twój komentarz, to znaczy)
Richard de Wit

1
Może to być problem z wersją, ale musiałem skomentować Twoje połączenie uwierzytelniające. Poza tym Twój komentarz działał jak mistrz! Po dalszych rozważaniach dotyczących testów stwierdziłem, że is_active, is_superuser i is_staff były niepotrzebne. To, co to zrobiło, to wywołanie set_password.
dolphus333
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.