2011-09-09 18 views
27

Ho iniziato a utilizzare il framework di test di Django e tutto funzionava fino a quando ho iniziato a testare le pagine autenticate.login() nel framework di test di Django

Per semplicità, diciamo che questa è una prova:

class SimpleTest(TestCase): 
    def setUp(self): 
     user = User.objects.create_user('temporary', '[email protected]', 'temporary') 

    def test_secure_page(self): 
     c = Client() 
     print c.login(username='temporary', password='temporary') 
     response = c.get('/users/secure/', follow=True) 
     user = User.objects.get(username='temporary') 
     self.assertEqual(response.context['email'], '[email protected]') 

Dopo ho eseguito questo test, non riesce, e vedo che la stampa di valore di ritorno di login() restituisce vero, ma response.content viene reindirizzato alla pagina di accesso (se l'accesso fallisce l'autenticazione decorator reindirizza alla pagina di accesso). Ho messo un punto di interruzione nel decoratore che fa l'autenticazione:

def authenticate(user): 
    if user.is_authenticated(): 
     return True 
    return False 

e in realtà restituisce False. La riga 4 in test_secure_page() recupera correttamente l'utente.

Questa è la funzione di visualizzazione:

@user_passes_test(authenticate, login_url='/users/login') 
def secure(request): 
    user = request.user 
    return render_to_response('secure.html', {'email': user.email}) 

Naturalmente, se provo ad entrare attraverso l'applicazione (al di fuori di prova), tutto funziona bene.

+1

E per favore pubblica il codice della vista che stai testando. –

+0

@ S.Lott Non stavo testando la mia pagina di accesso (anche se ho provato anche quello, ma non funziona neanche), ma il resto della parte "sicura" del sistema. Per questo motivo, ho provato ad usare login(). – kevin

+1

@kevin. Il problema è che il post di accesso crea un cookie che viene poi utilizzato dal client. Nessun cookie, nessun accesso sicuro. AFAIK, la funzione 'login()' non crea il cookie e lo restituisce al client. Puoi provare a riprodurre gli esempi nella documentazione di Django e vedere se funzionano per te? –

risposta

25

Il problema è che non si sta passando RequestContext al modello.

Inoltre, probabilmente è necessario utilizzare il decoratore login_required e il client integrato nella classe TestCase.

Mi piacerebbe riscrivere così:

#views.py 
from django.contrib.auth.decorators import login_required 
from django.shortcuts import render 

@login_required(login_url='/users/login') 
def secure(request): 
    user = request.user 
    return render(request, 'secure.html', {'email': user.email}) 



#tests.py 
class SimpleTest(TestCase): 
    def setUp(self): 
     user = User.objects.create_user('temporary', '[email protected]', 'temporary') 

    def test_secure_page(self): 
     self.client.login(username='temporary', password='temporary') 
     response = self.client.get('/manufacturers/', follow=True) 
     user = User.objects.get(username='temporary') 
     self.assertEqual(response.context['email'], '[email protected]') 
+1

Perché pensi che non passare RequestContext dovrebbe essere un problema (contesto è dato a render_to_response())? Funziona al di fuori del framework di testing quando viene richiamato dal browser (btw, ho provato a passare RequestContext, ma succede la stessa cosa). Inoltre, l'autenticazione avviene prima che venga inserita la vista. Ho provato anche @login_required e il client dalla classe TestCase, ma di nuovo succede la stessa cosa. – kevin

+0

L'ho fatto cambiando: self.assertEqual (response.context ['user']. Email, '[email protected]') – cor

10

Spesso può essere utile usare un backend di autenticazione personalizzato che bypassess qualsiasi tipo di autenticazione durante il test:

from django.contrib.auth.models import User 

class TestcaseUserBackend(object): 
    def authenticate(self, testcase_user=None): 
     return testcase_user 

    def get_user(self, user_id): 
     return User.objects.get(pk=user_id) 

Poi, durante i test , aggiungi yourapp.auth_backends.TestcaseUserBackend al vostro AUTHENTICATION_BACKENDS:

AUTHENTICATION_BACKENDS = [ 
    "akindi.testing.auth_backends.TestcaseUserBackend", 
] 

Poi, Durin g test, puoi semplicemente chiamare:

from django.contrib.auth import login 
user = User.objects.get(…) 
login(testcase_user=user) 
+0

Risposta eccellente. –

+1

get': login() ha un argomento di parole chiave inaspettato 'testcase_user'' qualche idea? – intelis

+0

Sei sicuro che 'login' è da' django.contrib.auth' (vedi post modificato)?E sei sicuro che il backend sia stato aggiunto correttamente? –

Problemi correlati