2016-01-06 11 views
13

Sto provando a eseguire i test di unità in Django. Ho il seguente modulo in index.html:Django render_to_string() ignora {% csrf_token%}

<form method=POST> 
    {% csrf_token %} 
    <input name=itemT> 
</form> 

E sto testando se la vista rendono il modello in modo corretto:

views.py

def homePage(request): 
    return render(request, 'index.html') 

tests.py:

request = HttpRequest() 

response = homePage(request) 
if response: 
    response = response.content.decode('UTF-8') 

expectedHTML = render_to_string('index.html') 
self.assertEqual(response, expectedHTML) 

Il response ha un campo di input nascosto con un token csrf; tuttavia, lo expectedHTML non esiste (c'è solo una riga vuota al posto di {% csrf_token %}). Quindi l'asserzione fallisce sempre.

È possibile avere render_to_string() generare un campo di input csrf? In tal caso, il token di response corrisponde a quello di expectedHTML?

Oppure, c'è un modo per ignorare il campo di input in modo che il test possa avere successo?

+3

Forse non è quello che ti serve, ma considera di cambiare il test. È la migliore idea per testare la risposta confrontando l'intero HTML all'interno della pagina del modello? Forse è meglio per te "assertContains" con i campi che devi veramente controllare. – PatNowak

+2

Il test sta solo verificando che 'render' rende un template allo stesso modo di' render_to_string'. Questo non è molto utile, perché ci saranno già dei test in Django per assicurarsi che 'render' e' render_to_string' funzionino. La cosa importante da testare è se la vista sta rendendo il modello corretto (puoi usare ['assertTemplateUsed'] (https://docs.djangoproject.com/en/1.9/topics/testing/tools/#django.test .SimpleTestCase.assertTemplateUsed)), oppure controlla il contenuto specifico nella risposta (usa 'assertContains'). – Alasdair

risposta

28

Per utilizzare il token csrf quando si utilizza render_to_string, è necessario fornire l'oggetto request in modo che i processori di contesto vengano eseguiti.

In Django 1.8+, si può semplicemente passare la richiesta come un argomento

return render_to_string('index.html', request=request) 

su versioni precedenti, è possibile utilizzare un RequestContext.

from django.template import RequestContext 
render_to_string('index.html', context_instance=RequestContext(request)) 
+1

'' context_instance'' è [deprecato da Django 1.8] (https://docs.djangoproject.com/en/1.9/topics/templates/#django.template.loader.render_to_string) per '' render_to_string''. Usa '' render_to_string ('index.html', request = request) '' invece. –

+0

@LutzPrechelt - Sì, non si dovrebbe usare 'context_instance' in Django 1.8+. Prima avevo scritto 'render' invece di' render_to_string'. Risolto ora. – Alasdair

+0

Grazie, è stato risolto un problema con un vecchio libro di test delle unità su cui stavo lavorando. – nighliber

4

È possibile semplicemente aggiungere un argomento come questo.

render_to_string('index.html', request=request) 

Fare riferimento allo document.

15

Questa risposta dovrebbe essere solo un commento, ma la pubblicazione di risposta come non ho abbastanza ripetizioni.

Purtroppo la risposta accettata non funziona con Django 1.10 le csrf_token modifiche su ogni richiesta. Si prega di vedere this gist che funziona su 1.10. (Ha modificato il codice un po 'per correggere l'errore dall'originale)

class HomePageTest(TestCase): 

    @staticmethod 
    def remove_csrf(html_code): 
     csrf_regex = r'<input[^>]+csrfmiddlewaretoken[^>]+>' 
     return re.sub(csrf_regex, '', html_code) 

    def assertEqualExceptCSRF(self, html_code1, html_code2): 
     return self.assertEqual(
      self.remove_csrf(html_code1), 
      self.remove_csrf(html_code2) 
     )