Jak napisać testy dla formularzy w Django?

110

Chciałbym symulować żądania do moich widoków w Django podczas pisania testów. Służy to głównie testowaniu formularzy. Oto fragment prostego żądania testowego:

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

Strona zawsze zwraca odpowiedź 200, niezależnie od tego, czy wystąpił błąd formularza, czy nie. Jak mogę sprawdzić, czy mój formularz nie powiódł się i czy w określonym polu ( soemthing) wystąpił błąd?

Mridang Agarwalla
źródło

Odpowiedzi:

250

Myślę, że jeśli chcesz tylko przetestować formularz, powinieneś po prostu przetestować formularz, a nie widok, w którym formularz jest renderowany. Przykład na pomysł:

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
źródło
62
+1. Ideą testów jednostkowych jest osobne testowanie każdej jednostki.
Daniel Roseman,
13
@Daniel Ale testy integracyjne są o wiele bardziej przydatne i częściej wychwytują błędy.
wobbily_col
19
@wobbily_col Również wykrycie rzeczywistego błędu w teście integracji zajmuje więcej czasu. W teście jednostkowym jest to bardziej oczywiste. Myślę, że do dobrego pokrycia testu potrzebujesz obu z nich.
Torsten Engelbrecht
11
Oto jak sprawdzić, czy nie ma konkretnego błędu formularza:self.assertEquals(form.errors['recipient'], [u"That recipient isn't valid"])
Emil Stenström
18
self.assertEqual(form.is_valid(), True)można uprościć: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.')

Gdzie „formularz” to nazwa zmiennej kontekstowej dla twojego formularza, „coś” to nazwa pola, a „To pole jest wymagane”. to dokładny tekst oczekiwanego błędu weryfikacji.

Shane
źródło
Powoduje to zgłoszenie błędu AttibuteError: AttributeError: Obiekt 'SafeUnicode' nie ma atrybutu 'errors'
sbaechler
dla początkujących użytkowników: utwórz wcześniej użytkownika i użyj go self.client.force_login(self.user)jako pierwszego wiersza w metodzie testowej.
sgauri
Miałem problem z tym postem (), a potem zorientowałem się, że muszę go wysłać jako wieloczęściowy jako odpowiedź = self.client.post ("/ form-url /", data = {'name': 'test123' , 'category': 1, 'note': 'note123'}, content_type = django.test.client.MULTIPART_CONTENT) Jeśli ktoś utknął z pobieraniem pustej instancji podczas zapisywania formularza, sprawdź żądania wysłane z przeglądarki
Ghaleb Khaled
17

Oryginalna odpowiedź z 2011 roku brzmiała

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

Ale widzę, że teraz (2018) jest cały tłum dostępnych twierdzeń :

  • assertRaisesMessage
  • assertFieldOutput
  • assertFormError
  • assertFormsetError

Wybieraj.

John Mee
źródło
+1 To działało dla mnie, gdy był to ogólny błąd formularza, który nie jest dołączany do pola.
Aaron Lelevier