test - ¿Cómo escribir una prueba unitaria para una vista django?
test form django (2)
Django se envía con un cliente de prueba que se puede usar para probar el ciclo de solicitud / respuesta completo: los documentos contienen un ejemplo de cómo hacer una solicitud de obtención a una url determinada y afirmar el código de estado así como el contexto de la plantilla. También necesitaría una prueba que realice un POST y afirme una redirección exitosa como se esperaba.
Tengo problemas para entender cómo deberían diseñarse las pruebas unitarias para django.
Desde mi comprensión, probar toda la vista de una vez parece imposible. Necesitamos distinguir entre los estados de solicitud pre y post. Pero no tengo idea de cómo diseñar esto. ¿Hay algún ejemplo de la vida real?
Al observar la documentación, los ejemplos son muy simplificados y solo se centran en el modelo.
@login_required
def call_view(request, contact_id):
profile = request.user.get_profile()
if request.POST:
form = CallsForm(profile.company, request.POST)
if form.is_valid()
return HttpResponseRedirect(''/contact/'' + contact_id + ''/calls/'')
else:
form = CallsForm(profile.company, instance=call)
variables = RequestContext(request, {''form'':form}
return render_to_response(''conversation.html'', variables)
actualizar:
tratando de hacer funcionar una prueba de éxito, pero aún falla:
def test_contact_view_success(self):
# same again, but with valid data, then
self.client.login(username=''username1'', password=''password1'')
response = self.client.post(''/contact/add/'', {u''last_name'': [u''Johnson''], })
self.assertRedirects(response, ''/'')
mensaje de error:
AssertionError: Response didn''t redirect as expected: Response code was 200 (expected 302)
Creo que esto se debe a que el form.is_valid () falla y no redirige, ¿correcto?
NB NB! Lo que describo a continuación no es estrictamente una "prueba de unidad"; es casi imposible escribir una prueba de unidad independiente para el código de vista de Django. Esto es más una prueba de integración ...
Tiene razón en que hay varios caminos a través de su vista:
-
GET
oPOST
por un usuario anónimo (debe redirigir a la página de inicio de sesión) -
GET
oPOST
por usuario conectado sin perfil (debe generar una excepciónUserProfile.DoesNotExist
) -
GET
por usuario registrado (debe mostrar el formulario) -
POST
por usuario conectado con datos en blanco (debería mostrar errores de formulario) -
POST
por usuario registrado con datos no válidos (debería mostrar errores de formulario) -
POST
por usuario registrado con datos válidos (debe redirigir)
La prueba 1 solo está probando @login_required
, por lo que podría omitirla. Tiendo a probarlo de todos modos (en caso de que yo o alguien más haya olvidado usar ese decorador).
No estoy seguro de que el caso de falla (una página de error 500) en 2 sea lo que realmente desea. En su lugar, averiguaría qué es lo que quiere que suceda (tal vez use get_or_create()
, o capture la excepción DoesNotExist
y cree un nuevo perfil de esa manera).
Dependiendo de la cantidad de validación personalizada que tenga, 4 puede que realmente no necesite ser probado.
En cualquier caso, dado todo lo anterior, haría algo como:
from django.test import TestCase
class TestCalls(TestCase):
def test_call_view_denies_anonymous(self):
response = self.client.get(''/url/to/view'', follow=True)
self.assertRedirects(response, ''/login/'')
response = self.client.post(''/url/to/view'', follow=True)
self.assertRedirects(response, ''/login/'')
def test_call_view_loads(self):
self.client.login(username=''user'', password=''test'') # defined in fixture or with factory in setUp()
response = self.client.get(''/url/to/view'')
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, ''conversation.html'')
def test_call_view_fails_blank(self):
self.client.login(username=''user'', password=''test'')
response = self.client.post(''/url/to/view'', {}) # blank data dictionary
self.assertFormError(response, ''form'', ''some_field'', ''This field is required.'')
# etc. ...
def test_call_view_fails_invalid(self):
# as above, but with invalid rather than blank data in dictionary
def test_call_view_fails_invalid(self):
# same again, but with valid data, then
self.assertRedirects(response, ''/contact/1/calls/'')
Obviamente, un inconveniente aquí son las URL codificadas. Puede usar reverse()
en sus pruebas o crear solicitudes utilizando RequestFactory
y llamar sus vistas como métodos (en lugar de por URL). Sin embargo, con el último método, aún necesita usar valores codificados o reverse()
para probar objetivos de redireccionamiento.
Espero que esto ayude.