Comment écrire des tests pour les formulaires dans Django?

110

Je voudrais simuler des requêtes à mes vues dans Django lorsque j'écris des tests. Il s'agit principalement de tester les formulaires. Voici un extrait d'une simple demande de test:

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 page renvoie toujours une réponse de 200, qu'il y ait ou non une erreur de formulaire. Comment puis-je vérifier que mon formulaire a échoué et que le champ particulier ( soemthing) contient une erreur?

Mridang Agarwalla
la source

Réponses:

250

Je pense que si vous souhaitez simplement tester le formulaire, vous devez simplement tester le formulaire et non la vue où le formulaire est rendu. Exemple pour se faire une idée:

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
la source
62
+1. L'idée des tests unitaires est de tester chaque unité séparément.
Daniel Roseman
13
@Daniel Mais les tests d'intégration sont bien plus utiles et plus susceptibles d'attraper des bogues.
wobbily_col
19
@wobbily_col Il faut également plus de temps pour repérer quel est le bogue réel dans un test d'intégration. Dans un test unitaire, c'est plus évident. Je pense que pour une bonne couverture de test, vous avez de toute façon besoin des deux.
Torsten Engelbrecht
11
Voici comment vérifier une erreur de formulaire spécifique:self.assertEquals(form.errors['recipient'], [u"That recipient isn't valid"])
Emil Stenström
18
self.assertEqual(form.is_valid(), True)pourrait être simplifié: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.')

Où «formulaire» est le nom de la variable de contexte de votre formulaire, «quelque chose» est le nom du champ et «Ce champ est obligatoire». est le texte exact de l'erreur de validation attendue.

Shane
la source
Cela déclenche une AttibuteError pour moi: AttributeError: l'objet 'SafeUnicode' n'a pas d'attribut 'errors'
sbaechler
pour les utilisateurs débutants: créez un utilisateur au préalable et utilisez-le self.client.force_login(self.user)comme première ligne dans la méthode de test.
sgauri
J'ai eu un problème avec ce post (), puis j'ai compris que je devais l'envoyer en plusieurs parties comme suit response = self.client.post ("/ form-url /", data = {'name': 'test123' , 'category': 1, 'note': 'note123'}, content_type = django.test.client.MULTIPART_CONTENT) Si l'un d'entre eux est bloqué par l'obtention d'une instance vide lors de l'enregistrement du formulaire, vérifiez les demandes envoyées par le navigateur
Ghaleb Khaled
17

La réponse originale de 2011 était

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

Mais je vois maintenant (2018) qu'il y a toute une foule d'assertions applicables disponibles :

  • assertRaisesMessage
  • assertFieldOutput
  • assertFormError
  • assertFormsetError

Faites votre choix.

John Mee
la source
+1 Cela a fonctionné pour moi lorsqu'il s'agissait d'une erreur de formulaire générale qui n'est pas attachée à un champ.
Aaron Lelevier