Selenium tests with Django 1.4+
With Django 1.4 support for in-browser testing frameworks, it was time to revisit our previous blog posts dedicated to Selenium: Selenium, Python and Jenkins on Debian 1, 2 and 3.
Sample project
This tutorial is based on the poll application from the Django tutorial. It describes all the required steps to run Selenium tests on a Django 1.4+ project, keeping in mind that the final step is to use Jenkins as a continuous integration server. The source code can be found on the django14
branch of this repository.
This sample project is organized as follows:
The following features are implemented:
- Poll management via the Django admin site,
- Vote submission.
Testing tools
In this tutorial, the following tools are used:
- django-jenkins: a Django test runner dedicated to Jenkins,
- coverage (via
django-jenkins
): a tool for measuring code coverage of Python programs, - pylint (via
django-jenkins
): a static code analyzer looking for bugs and signs of poor code quality.
Installation
First clone the repository:
$ git clone -b django14 https://github.com/shiningpanda/djangotutorial-selenium.git
Step in the new djangotutorial-selenium
folder, and install all requirements with pip by typing:
$ pip install -r requirements.txt
Configure tests
Edit djangotutorial/settings.py
to enable django_jenkins
in the INSTALLED_APPS
, then define the applications you want to test with the PROJECT_APPS
settings. In this example we want to test the poll
application:
INSTALLED_APPS = (
# Other applications...
'django_jenkins',
)
# Other settings...
PROJECT_APPS = [
'polls',
]
Write tests
Selenium tests are located in the polls/tests.py
module.
All our tests inherit from the following django.test.LiveServerTestCase base class, which launch a live Django server in the background on setup, and shuts it down on teardown.
from django.test import LiveServerTestCase
from selenium.webdriver.firefox.webdriver import WebDriver
class BaseTestCase(LiveServerTestCase):
@classmethod
def setUpClass(cls):
cls.driver = WebDriver()
super(BaseTestCase, cls).setUpClass()
@classmethod
def tearDownClass(cls):
super(BaseTestCase, cls).tearDownClass()
cls.driver.quit()
A template to write your tests:
class SampleTestCase(BaseTestCase):
def test(self):
self.driver.get(self.live_server_url)
# Your test here...
Then just write your tests as usual, with the benefit of having the self.driver
directly available.
The following sections contain the test examples of two major features:
- vote submission,
- login on admin site.
Test vote submission
The project defines a sample poll ShiningPanda is a...
in the polls/fixtures/initial_data.json
fixture which is loaded at database initialization.
This test verifies that the voting process is working for this poll:
class PollsTestCase(BaseTestCase):
def test_vote(self):
self.driver.get(self.live_server_url + '/polls/')
poll = self.driver.find_element_by_link_text('ShiningPanda is a...')
poll.click()
time.sleep(2) # Should use accurate WebDriverWait
choices = self.driver.find_elements_by_name('choice')
self.assertEquals(3, len(choices))
choices[2].click()
choices[2].submit()
lis = self.driver.find_elements_by_tag_name('li')
self.assertEquals(3, len(lis))
self.assertEquals('Hosted CI service? -- 0 votes', lis[0].text)
self.assertEquals('Consulting firm? -- 0 votes', lis[1].text)
self.assertEquals('Both! -- 1 vote', lis[2].text)
- First open the page listing the polls:
http://localhost:8000/polls/
, - Search the link pointing to the
ShiningPanda is a...
poll, and click on it, - Verify that three choices are available, then select the last one before submitting the form,
- Finally verify the vote results on the poll result page.
Test admin site login
The project also defines an administrator admin/admin
in the polls/fixtures/initial_data.json
fixture which is loaded at database initialization.
This test checks that the admin
user can log into the admin site:
class AdminTestCase(BaseTestCase):
def test_login(self):
self.driver.get(self.live_server_url + '/admin/')
self.driver.find_element_by_id('id_username').send_keys('admin')
password = self.driver.find_element_by_id('id_password')
password.send_keys('admin')
password.submit()
time.sleep(2)
self.assertTrue(self.driver.find_element_by_id('user-tools').text.startswith('Welcome'))
- First open the administration interface login page:
http://localhost:8000/admin/
, - Then look for the field dedicated to username (has an id
id_username
) and typeadmin
, - Then look for the field dedicated to password (has an id
id_password
) and typeadmin
before submitting the form, - Finally assert that the user is welcomed.
Run tests
To run the test, just execute:
$ python manage.py jenkins
Creating test database for alias 'default'...
..
----------------------------------------------------------------------
Ran 2 tests in 13.018s
OK
Destroying test database for alias 'default'...
What's next?
In our next blog post, how to integrate this project with Jenkins!