6

If I have a test like so...

 def test_home_page_returns_correct_html(self):
        request = HttpRequest()
        response = home_page(request)
        expected_html = render_to_string('home.html', request=request)
        self.assertEqual(response.content.decode(), expected_html)

As soon as I add a form in curly braces, e.g. {{ form }} The above test will fail as the .html file will not render the form only the response will. Thus causing the assertion to not match. Is there a way round this so that I can still test my html against the response?

Reiss Johnson
  • 1,419
  • 1
  • 13
  • 19
  • render_to_string supports a dictionary as second parameter or using context keyword which will be used as context to render the template. You will have to send the form in the context dictionary. See [django docs](https://docs.djangoproject.com/en/1.9/topics/templates/#django.template.loader.render_to_string) – Gabriel Muj May 21 '16 at 13:13
  • 1
    This seems a bit of a strange test though. It seems you're duplicating the code of the view, then checking they give the same result. Why? What is this supposed to be testing? – Daniel Roseman May 21 '16 at 14:35

1 Answers1

27

You can pass a form instance to the render_to_string function:

from django.template import RequestContext
from django.template.loader import render_to_string

form = ModelForm()
context = RequestContext(request, {'form': form})
expected_html = render_to_string('home.html', context)

Usually what I do is splitting this kind of test into several other tests, like this:

Using from django.test import TestCase

def setUp(self):
    self.user = User.objects.create_user('john', 'john@doe.com', '123')
    self.client.login(username='john', password='123')
    self.response = self.client.get(r('home'))

First test which template was used:

def test_template(self):
    self.assertTemplateUsed(self.response, 'home.html')

Test the form:

def test_has_form(self):
    form = self.response.context['form']
    self.assertIsInstance(form, CreateModelForm)

And then I test the key parts of the HTML:

def test_html(self):
    self.assertContains(self.response, '<form')
    self.assertContains(self.response, 'type="hidden"', 1)
    self.assertContains(self.response, 'type="text"', 2)
    self.assertContains(self.response, 'type="radio"', 3)
    self.assertContains(self.response, 'type="submit"', 1)

Finally if the rendered template has a csrf token:

def test_csrf(self):
    self.assertContains(self.response, 'csrfmiddlewaretoken')
Vitor Freitas
  • 3,550
  • 1
  • 24
  • 35
  • 1
    When I do `response.context['form']` , it says `form` is an invalid key. Are you manually setting it some where? – saadi Oct 15 '19 at 10:52