Dugan Chen's Homepage

Various Things

Using Django with Selenium

Much has been written about the ways to integrate Django with Selenium. Here’s my attempt.

First, I was inspired by harry’s fantastic Test-Driven-Django Tutorial and GitHub page. I am also aware of django-selenium and django-nose-selenium, but have not used them.

Now, for functional testing, you want Selenium. Most guides to testing with Selenium recommend integrating it with a unit testing framework (for example, PHPUnit for a PHP project), so that you can assert that a DOM element has a certain value after a certain set of mouse clicks. You will also want your Selenium scripts to be integrated with Django’s settings, so that you have access, to say, the urlresolvers and the data model.

These requirements are easy to meet. How do you give a script access to Django’s settings? Easy. Set it to run from manage.py.. To integrate Selenium scripts with the unit testing frameworld, you can simply run them from TestCases. To add the management command, you create the following heirarchy of nested modules and packages: functional_test/management/commands/functional_test.py

Our test loader and runner will be functional_test.py. This version expects all functional tests to be in a module called “tests”. This could become unwieldy, and is a candidate for being improved.

from django.core.management.base import BaseCommand
from functional_tests import tests
from unittest import TestLoader, TextTestRunner

class Command(BaseCommand):

    args = '<test>'
    help = 'Runs a functional test'

    def handle(self, *args, **options):
        for test_name in args:
            try:
                test_case = getattr(tests, test_name)
            except AttributeError:
                print 'Test not found'
                return

            loader = TestLoader() 
            suite = loader.loadTestsFromTestCase(test_case)
            runner = TextTestRunner(verbosity=2)
            runner.run(suite)

And here is a sample test contained in functional_tests/tests.py:

from unittest import TestCase
from django.core.urlresolvers import reverse
from selenium.webdriver import Chrome
from time import sleep

SITE_ROOT = 'http://localhost:8000/projectname'

class Home(TestCase):

    def setUp(self):
        self.browser = Chrome()

    def test_signup(self):
        self.browser.get('{0}{1}'.format(reverse('home'))
        element = self.browser.find_element_by_tag_name('h1')
        self.assertEquals('H1 Value', element.text)

    def tearDown(self):
        sleep(0.2)
        self.browser.close()

With the development server running, you launch this test with the following command:

python manage.py functional_test Home