Comment écrire un test unitaire pour une vue django?

J’ai du mal à comprendre comment les tests unitaires devraient être conçus pour le django.

D’après ce que je sais, tester toute la vue en une seule fois semble impossible. Nous devons faire la distinction entre les états de pré-post et de post-demande. Mais je ne sais pas comment concevoir cela. Y a-t-il un exemple concret?

En regardant la documentation, les exemples sont trop simplifiés et ne portent que sur le modèle.

@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) 

mettre à jour:

essayer de faire un test de réussite, mais cela échoue toujours:

 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, '/') 

Message d’erreur:

 AssertionError: Response didn't redirect as expected: Response code was 200 (expected 302) 

Je pense que c’est parce que le form.is_valid () échoue et qu’il ne redirige pas, n’est-ce pas?

NB NB! Ce que je décris ci-dessous n’est pas ssortingctement un “test unitaire”; il est presque impossible d’écrire un test d’unité indépendant pour le code de vue Django. Ceci est plus un test d’intégration …

Vous avez raison de dire qu’il existe plusieurs voies à travers votre vue:

  1. GET ou POST par un utilisateur anonyme (devrait redirect vers la page de connexion)
  2. GET ou POST par l’utilisateur connecté sans profil (doit générer une exception UserProfile.DoesNotExist )
  3. GET par utilisateur connecté (devrait afficher le formulaire)
  4. POST par l’utilisateur connecté avec des données vides (doit afficher des erreurs de formulaire)
  5. POST par l’utilisateur connecté avec des données non valides (doit afficher des erreurs de formulaire)
  6. POST par l’utilisateur connecté avec des données valides (redirect)

Tester 1 est vraiment un test de @login_required , vous pouvez donc le sauter. J’ai tendance à le tester quand même (juste au cas où moi ou quelqu’un d’autre aurait oublié d’utiliser ce décorateur).

Je ne suis pas sûr que le cas d’échec (une page d’erreur de 500) en 2 soit ce que vous voulez vraiment. Je travaillerais plutôt sur ce que vous voulez faire ( utilisez peut- être get_or_create() , ou attrapez l’exception DoesNotExist et créez un nouveau profil de cette façon).

Selon la quantité de validation personnalisée dont vous disposez, 4 n’ont peut-être pas besoin d’être testés.

En tout cas, compte tenu de tout ce qui précède, je ferais quelque chose comme:

 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/') 

De toute évidence, un inconvénient réside dans les URL codées en dur. Vous pouvez utiliser reverse() dans vos tests ou générer des requêtes à l’aide de RequestFactory et appeler vos vues en tant que méthodes (plutôt que par URL). Avec cette dernière méthode, cependant, vous devez toujours utiliser des valeurs codées en dur ou reverse() pour tester les cibles de redirection.

J’espère que cela t’aides.

Django est livré avec un client de test qui peut être utilisé pour tester le cycle de demande / réponse complet: Les documents contiennent un exemple de demande de requête sur une URL donnée et d’affirmation du code d’état ainsi que du contexte du modèle. Vous auriez également besoin d’un test qui effectue un POST et affirme une redirection réussie comme prévu.