Djangos self.client.login (…) funktioniert nicht in Unit-Tests


83

Ich habe Benutzer für meine Komponententests auf zwei Arten erstellt:

1) Erstellen Sie ein Fixture für "auth.user", das ungefähr so ​​aussieht:

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

Ich habe die scheinbar unwichtigen Teile weggelassen.

2) Verwenden Sie 'create_user' in der setUp-Funktion (obwohl ich lieber alles in meiner Fixtures-Klasse behalten möchte):

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

Beachten Sie, dass das Passwort in beiden Fällen simpson ist.

Ich habe überprüft, ob diese Informationen immer wieder korrekt in die Testdatenbank geladen werden. Ich kann das User-Objekt mit User.objects.get abrufen. Ich kann mit 'check_password' überprüfen, ob das Passwort korrekt ist. Der Benutzer ist aktiv.

Self.client.login (Benutzername = 'Homer', Passwort = 'Simpson') schlägt jedoch immer fehl. Ich bin verblüfft, warum. Ich glaube, ich habe jede einzelne diesbezügliche Internetdiskussion gelesen. Kann jemand helfen?

Der Login-Code in meinem Unit-Test sieht folgendermaßen aus:

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

Vielen Dank.


1
Was ist die Fehlermeldung, die Sie erhalten haben?
zs2020

Der Testfall schlägt in der Zeile 'self.assertTrue (login)' fehl. Die Funktion login () gibt False zurück.
Thebossman

1
Ich habe im Grunde Ihre 2. Variante kopiert und eingefügt und sie funktioniert auf Django 1.3. Können Sie den gesamten Code einschließlich der Importe veröffentlichen?
Liorsion

Dies wurde irgendwo in einer Codebasis vergraben, auf die ich nicht mehr zugreifen kann. Wenn ich auf das Problem stoße, werde ich es sicher weiterverfolgen, aber für die Aufzeichnung war es mit einer früheren Version von Django; Ich denke 1.0.2.
Thebossman

Antworten:


119

Der Code, der nicht funktioniert:

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

Warum funktioniert es nicht?

Im obigen Snippet wird beim UserErstellen von der tatsächliche Kennwort-Hash auf gesetzt 12345. Wenn der Client die loginMethode aufruft , wird der Wert des passwordArguments 12345durch die Hash-Funktion übergeben, was zu so etwas wie führt

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

Dies wird dann mit dem in der Datenbank gespeicherten Hash verglichen, und dem Client wird der Zugriff verweigert, weil 'adkfh5lkad438....' != '12345'

Die Lösung

Am besten rufen Sie die set_passwordFunktion auf, die den angegebenen String durch die Hash-Funktion leitet und das Ergebnis in speichert User.password.

Außerdem set_passwordmüssen wir nach dem Aufruf das aktualisierte UserObjekt in der Datenbank speichern:

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

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

44
Sie eine Verwendung User.objects.create_superuser()und User.objects.create_user()die genau diesen set_password()Anruf ausführen .
Vdboor

Wie wäre es, wenn Sie eine Person anmelden
Rocky Raccoon

um @vdboor Kommentar hinzuzufügen: Beachten Sie, dass Django 1.4 auch User.objects.get_or_create()den erforderlichen set_password()Aufruf ausführt
Furins

51

Eine einfachere Möglichkeit ist die Verwendung force_login, neu in Django 1.9.

force_login(user, backend=None)

Zum Beispiel:

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

5

Können Sie wie unten überprüfen,

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)

Dieser Testfall hat bei mir funktioniert.


5

Überprüfen Sie, ob dies django.contrib.sessionshinzugefügt wurde, INSTALLED_APPSda client.login()überprüft wird, ob dies der Fall ist und immer false zurückgibt, wenn dies nicht der Fall ist:

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


2
+1 dafür. Selbst django.contrib.sessions.middleware.SessionMiddlewarein Middleware-Klassen können Sie sich nicht über django.test.Client anmelden. Ich brauche eine Woche, um diese Antwort zu finden
Schüler

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

Wenn jemand dies noch verfolgt, sollten die Attribute 'is_staff' und 'is_active' für eine erfolgreiche Anmeldung auf True gesetzt bleiben.

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


4
Dies hat gerade funktioniert ........... self.user = User.objects.create (Benutzername = 'Testbenutzer', Passwort = '12345', is_active = True, is_staff = True, is_superuser = True) self. user.set_password ('hallo') self.user.save () user = authentifizieren (Benutzername = 'Testbenutzer', Passwort = 'Hallo') login = self.c.login (Benutzername = 'Testbenutzer', Passwort = 'Hallo' ) self.assertTrue (Login)
Arindam Roychowdhury

Dies hat nichts damit zu tun, is_staffwas definiert, ob der Zugriff auf das Admin-Panel im Allgemeinen gewährt wird. Wie Sie sehen können, haben die Daten in der Erstbuchung bereits is_active = 1und das ist auch die Standardeinstellung für User.objects.create().
jnns

1
@arindamroychowdhury - Wow, das hat tatsächlich funktioniert .. (Ihr Kommentar, das heißt)
Richard de Wit

1
Es könnte ein Versionsproblem sein, aber ich musste Ihren Authentifizierungsanruf auskommentieren. Davon abgesehen hat Ihr Kommentar wie ein Champion funktioniert! Bei weiteren Tests stellte ich fest, dass is_active, is_superuser und is_staff alle unnötig waren. Das, was es getan hat, war der Aufruf von set_password.
Delphus333
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.