¿Cómo debo escribir pruebas para formularios en Django?

109

Me gustaría simular solicitudes a mis vistas en Django cuando estoy escribiendo pruebas. Esto es principalmente para probar los formularios. Aquí hay un fragmento de una solicitud de prueba simple:

from django.tests import TestCase

class MyTests(TestCase):
    def test_forms(self):
        response = self.client.post("/my/form/", {'something':'something'})
        self.assertEqual(response.status_code, 200) # we get our page back with an error

La página siempre devuelve una respuesta de 200, ya sea que haya un error de formulario o no. ¿Cómo puedo comprobar que mi formulario falló y que el campo en particular ( soemthing) tuvo un error?

Mridang Agarwalla
fuente

Respuestas:

250

Creo que si solo desea probar el formulario, debe probar el formulario y no la vista donde se representa. Ejemplo para hacerse una idea:

from django.test import TestCase
from myapp.forms import MyForm

class MyTests(TestCase):
    def test_forms(self):
        form_data = {'something': 'something'}
        form = MyForm(data=form_data)
        self.assertTrue(form.is_valid())
        ... # other tests relating forms, for example checking the form data
Torsten Engelbrecht
fuente
62
+1. La idea de las pruebas unitarias es probar cada unidad por separado.
Daniel Roseman
13
@Daniel Pero las pruebas de integración son mucho más útiles y tienen más probabilidades de detectar errores.
wobbily_col
19
@wobbily_col También lleva más tiempo detectar cuál es el error real en una prueba de integración. En una prueba unitaria es más obvio. Sin embargo, creo que para una buena cobertura de prueba necesitas ambos.
Torsten Engelbrecht
11
Así es como se comprueba si hay un error de formulario específico:self.assertEquals(form.errors['recipient'], [u"That recipient isn't valid"])
Emil Stenström
18
self.assertEqual(form.is_valid(), True)podría simplificarse:self.assertTrue(form.is_valid())
Adam Taylor
76

https://docs.djangoproject.com/en/stable/topics/testing/tools/#django.test.SimpleTestCase.assertFormError

from django.tests import TestCase

class MyTests(TestCase):
    def test_forms(self):
        response = self.client.post("/my/form/", {'something':'something'})
        self.assertFormError(response, 'form', 'something', 'This field is required.')

Donde "formulario" es el nombre de la variable de contexto para su formulario, "algo" es el nombre del campo y "Este campo es obligatorio". es el texto exacto del error de validación esperado.

Shane
fuente
Esto genera un AttibuteError para mí: AttributeError: El objeto 'SafeUnicode' no tiene ningún atributo 'errores'
sbaechler
para usuarios novatos: cree un usuario de antemano y utilícelo self.client.force_login(self.user)como primera línea en el método de prueba.
sgauri
Tuve un problema con esta publicación (), luego descubrí que tenía que enviarlo como multiparte como sigue response = self.client.post ("/ form-url /", data = {'name': 'test123' , 'category': 1, 'note': 'note123'}, content_type = django.test.client.MULTIPART_CONTENT) Si alguno se atasca con obtener una instancia vacía al guardar el formulario, verifique las solicitudes enviadas desde el navegador
Ghaleb Khaled
17

La respuesta original de 2011 fue

self.assertContains(response, "Invalid message here", 1, 200)

Pero veo ahora (2018) que hay una gran cantidad de afirmaciones aplicables disponibles :

  • assertRaisesMessage
  • asertFieldOutput
  • asertFormError
  • asertFormsetError

Elige tu opción.

John Mee
fuente
+1 Esto funcionó para mí cuando era un error de formulario general que no se adjuntaba a un campo.
Aaron Lelevier