2013-04-22 5 views
19

Ich habe Tests für eine meiner Django-Anwendungen geschrieben und habe versucht, dieses Problem seit einiger Zeit zu umgehen. Ich habe eine Ansicht, die Nachrichten mit django.contrib.messages für verschiedene Fälle sendet. Die Ansicht sieht ungefähr wie folgt aus.Django Testing - Prüfe Nachrichten für eine Ansicht, die umleitet

from django.contrib import messages 
from django.shortcuts import redirect 

import custom_messages 

def some_view(request): 
    """ This is a sample view for testing purposes. 
    """ 

    some_condition = models.SomeModel.objects.get_or_none(
     condition=some_condition) 
    if some_condition: 
     messages.success(request, custom_message.SUCCESS) 
    else: 
     messages.error(request, custom_message.ERROR) 
    redirect(some_other_view) 

Jetzt, während diese client.get ‚s Antwort Ansicht Prüfung nicht das context Wörterbuch enthalten, die die messages enthält als diese Ansicht eine Umleitung verwendet. Für Ansichten, die Vorlagen rendern, können wir mit messages = response.context.get('messages') auf die Nachrichtenliste zugreifen. Wie erhalten wir Zugriff auf messages für eine Ansicht, die umleitet?

+0

Nicht sicher, ob dies Ihren Bedarf passen, aber Sie können Variablen erhalten zu identifizieren passieren, was passiert ist: 'umleiten (Reverse (some_other_view) + '? user_added = true') ' –

+0

Ich teste gerade die Bedingung, die in der Ansicht in meinem Test verwendet wird. Hier spreche ich über das explizite Testen der Nachricht, die gesendet wurde. – Amyth

Antwort

31

Verwenden Sie die follow=True Option im client.get() Aufruf, und der Client wird die Umleitung folgen. Sie können dann testen, ob sich die Nachricht im Kontext der Ansicht befindet, an die Sie weitergeleitet wurden.

def test_some_view(self): 
    # use follow=True to follow redirect 
    response = self.client.get('/some-url/', follow=True) 

    # don't really need to check status code because assertRedirects will check it 
    self.assertEqual(response.status_code, 200) 
    self.assertRedirects(response, '/some-other-url/') 

    # get message from context and check that expected text is there 
    message = list(response.context.get('messages'))[0] 
    self.assertEqual(message.tags, "success") 
    self.assertTrue("success text" in message.message) 
+0

Danke, das hat funktioniert. Mit 'follow = True' ändert sich jedoch der erwartete Umleitungscode von '302' zu '200', da er der umgeleiteten Ansicht folgt. – Amyth

+0

Ja, nach der Weiterleitung bedeutet dies, dass die Antwort den Statuscode 200 hat. Es gibt ein ['assertRedirects'] (https://docs.djangoproject.com/en/1.5/topics/testing/overview/#django.test.TestCase .assertRedirects) Methode, mit der Sie die Weiterleitung testen können. – Alasdair

+0

yup, das ist, was ich jetzt benutze :) – Amyth

1

Wenn Ihre Ansichten umleiten und Sie follow=true in Ihrer Anfrage an den Test-Client verwenden, die oben nicht funktioniert. Ich schrieb eine Hilfsfunktion, um die erste (und in meinem Fall einzige) Nachricht zu erhalten, die mit der Antwort gesendet wurde.

@classmethod 
def getmessage(cls, response): 
    """Helper method to return message from response """ 
    for c in response.context: 
     message = [m for m in c.get('messages')][0] 
     if message: 
      return message 

Sie umfassen diese in Ihrer Testklasse und es wie folgt verwendet werden:

message = self.getmessage(response) 

Wo response ist, was man eine bekommen von hinten get oder post zu einem Client.

Dies ist ein wenig zerbrechlich, aber hoffentlich rettet es jemand anderes einige Zeit.

+2

Sie brauchen dieses Listenverständnis nicht, verwenden Sie nur Listen (Nachrichten) oder Tupel (Nachrichten). – bbrik

1

Ich hatte das gleiche Problem bei der Verwendung einer 3rd Party App.

Wenn Sie die Nachrichten aus einer Sicht zu bekommen, die ein HttpResponseRedict zurückgibt (aus dem Sie den Kontext nicht zugreifen können) aus einer anderen Sicht können Sie get_messages(request)

from django.contrib.messages import get_messages 

storage = get_messages(request) 
for message in storage: 
    do_something_with_the_message(message) 

Dies löscht den Nachrichtenspeicher verwenden aber so, wenn Sie die Nachrichten aus einer Vorlage zugreifen möchten später hinzu:

storage.used = False 
4

Sie get_messages verwenden können() mit response.wsgi_request wie folgt aus (getestet in Django 1.10):

from django.contrib.messages import get_messages 
... 
def test_view(self): 
    response = self.client.get('/some-url/') # you don't need follow=True 
    self.assertRedirects(response, '/some-other-url/') 
    # each element is an instance of django.contrib.messages.storage.base.Message 
    all_messages = [msg for msg in get_messages(response.wsgi_request)] 

    # here's how you test the first message 
    self.assertEqual(all_messages[0].tags, "success") 
    self.assertEqual(all_messages[0].message, "you have done well") 
+0

Das funktionierte für mich, während die Methode von Alasdair keine Nachrichten zeigte. Ich bin auf Django 1.11. –

0

Alternative Methode spöttische Nachrichten (muss nicht umleiten folgen):

from mock import ANY, patch 
from django.contrib import messages 

@patch('myapp.views.messages.add_message') 
def test_some_view(self, mock_add_message): 
    r = self.client.get('/some-url/') 
    mock_add_message.assert_called_once_with(ANY, messages.ERROR, 'Expected message.') # or assert_called_with, assert_has_calls... 
Verwandte Themen