17
votes

I'm writing unit tests for my Django application. However, I don't know how to test the HTML output of a view.

Sometimes I might want to check if a specific element contains certain value, or how many of those elements are displayed, or things like that. How can I do such tests?

I would like a solution that uses unittest and django's own django.test.

I know I can use Selenium or Pyccuracy (which uses Selenium), but Selenium tests are quite slow because of the huge overhead of launching a browser. Also, unit tests work out-of-the-box with django-coverage package.

4

4 Answers

12
votes

I've always found a combination of BeautifulSoup, and assertContains and assertFormError from TestCase's available assertions to do the trick.

12
votes

These other answers are now out of date regarding assertions. The assertion assertHTMLEqual (since Django 1.4) takes care of things like ignoring whitespace, and ignoring the order of attributes.

For example (from the docs):

from django.test import TestCase

class MyTest(TestCase):

    def test_some_html(self):
        # A passing test that doesn't raise an AssertionError.
        self.assertHTMLEqual(
            '<input type="checkbox" checked="checked" id="id_accept_terms" />',
            '<input id="id_accept_terms" type="checkbox" checked>'
        )

In practice, one of the arguments to assertHTMLEqual would be dynamically generated.

9
votes

Django's test framework is ideal for this.

  1. Check the status code and content. http://docs.djangoproject.com/en/1.2/topics/testing/#django.test.TestCase.assertContains

  2. Check the template. http://docs.djangoproject.com/en/1.2/topics/testing/#django.test.TestCase.assertTemplateUsed

Also, it helps to use id="something" tags within your HTML to make it easier to find things when unit testing. We have tests like this.

def should_find_something( self ):
    response= self.client.get( "/path/to/resource/pk/" )
    self.assertContains( response, '<td id="pk">the pk string</td>', status_code=200 )
    self.assertTemplateUsed( response, 'appropriate_page.html' )

Works nicely.

1
votes