2013-04-22 23 views
19

Ho scritto dei test per una delle mie applicazioni di django e ho cercato di risolvere questo problema già da un po 'di tempo. Ho una vista che invia messaggi usando django.contrib.messages per casi diversi. La vista assomiglia a quanto segue.Test di Django - controlla i messaggi per una vista che reindirizza

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) 

Ora, durante la prova di questa risposta vista s' client.get non contiene il dizionario context che contiene il messages come questo punto di vista utilizza un reindirizzamento. Per le viste che eseguono il rendering dei modelli, è possibile accedere all'elenco dei messaggi utilizzando messages = response.context.get('messages'). Come possiamo ottenere l'accesso a messages per una vista che reindirizza?

+0

Non so se questo si adatta al vostro bisogno, ma si può passare ottenere le variabili per identificare ciò che è successo: 'redirect (inverso (some_other_view) + '? user_added = true') ' –

+0

In realtà sto già testando la condizione utilizzata nella vista del mio test. Qui sto parlando di testare esplicitamente il messaggio che è stato inviato. – Amyth

risposta

31

Utilizzare l'opzione follow=True nella chiamata client.get() e il client seguirà il reindirizzamento. È quindi possibile verificare che il messaggio sia nel contesto della vista a cui è stato reindirizzato.

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

Grazie, ha funzionato. Però, usando 'follow = True' cambia il codice di reindirizzamento atteso da' 302' a '200' come segue la vista reindirizzata. – Amyth

+0

Sì, seguendo il reindirizzamento significa che la risposta ha il codice di stato 200. Esiste un ['assertRedirects'] (https://docs.djangoproject.com/en/1.5/topics/testing/overview/#django.test.TestCase .assertRedirects) metodo che è possibile utilizzare per testare il reindirizzamento. – Alasdair

+0

sì, questo è quello che sto usando ora :) – Amyth

1

Se le vostre opinioni stanno riorientando e si utilizza follow=true nella richiesta per il client di prova di cui sopra non funziona. Ho finito per scrivere una funzione di supporto per ottenere il primo (e nel mio caso, solo) messaggio inviato con la risposta.

@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 

si include questo all'interno della vostra classe di test e usare in questo modo:

message = self.getmessage(response) 

Dove response è quello che si ottiene di ritorno da un get o post ad un Client.

Questo è un po 'fragile ma si spera che risparmi qualcun altro un po' di tempo.

+2

Non hai bisogno di quella comprensione di lista, basta usare lista (messaggi) o tupla (messaggi). – bbrik

1

Ho avuto lo stesso problema quando uso un'app di terze parti.

Se si desidera ottenere i messaggi da una vista che restituisce un HttpResponseRedict (da cui non è possibile accedere al contesto) dall'interno di un'altra vista, è possibile utilizzare get_messages(request)

from django.contrib.messages import get_messages 

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

Questo cancella la memorizzazione di messaggi però, quindi se si desidera accedere ai messaggi da un modello più tardi, aggiungere:

storage.used = False 
4

È possibile utilizzare get_messages() con response.wsgi_request come questo (testato 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

Questo ha funzionato per me, mentre il metodo di Alasdair non mostrava alcun messaggio. Sono su Django 1.11. –

0

alternativi metodo beffardo messaggi (non ha bisogno di seguire reindirizzamento):

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...