Browse files

Added a default test Client to TestCase, and added some assertions fo…

…r some common testing patterns.

git-svn-id: bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent e986e8a commit a0ef3ba2f7e815b4f3617f6e2827f66c13de3194 @freakboy3742 freakboy3742 committed May 5, 2007
Showing with 81 additions and 18 deletions.
  1. +31 −1 django/test/
  2. +46 −8 docs/testing.txt
  3. +4 −9 tests/modeltests/test_client/
@@ -1,8 +1,10 @@
import re, doctest, unittest
+from urlparse import urlparse
from django.db import transaction
from django.core import management
from django.db.models import get_apps
+from django.test.client import Client
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
class OutputChecker(doctest.OutputChecker):
@@ -46,5 +48,33 @@ def run(self, result=None):
+ self.client = Client()
super(TestCase, self).run(result)
+ def assertRedirects(self, response, expected_path):
+ """Assert that a response redirected to a specific URL, and that the
+ redirect URL can be loaded.
+ """
+ self.assertEqual(response.status_code, 302,
+ "Response didn't redirect: Reponse code was %d" % response.status_code)
+ scheme, netloc, path, params, query, fragment = urlparse(response['Location'])
+ self.assertEqual(path, expected_path,
+ "Response redirected to '%s', expected '%s'" % (path, expected_path))
+ redirect_response = self.client.get(path)
+ self.assertEqual(redirect_response.status_code, 200,
+ "Couldn't retrieve redirection page '%s'" % path)
+ def assertContains(self, response, text, count=1):
+ """Assert that a response indicates that a page was retreived successfully,
+ (i.e., the HTTP status code was 200), and that ``text`` occurs ``count``
+ times in the content of the response.
+ """
+ self.assertEqual(response.status_code, 200,
+ "Couldn't retrieve page'")
+ real_count = response.content.count(text)
+ self.assertEqual(real_count, count,
+ "Could only find %d of %d instances of '%s' in response" % (real_count, count, text))
@@ -166,7 +166,7 @@ To assist in testing various features of your application, Django provides
tools that can be used to establish tests and test conditions.
* `Test Client`_
-* Fixtures_
+* `TestCase`_
Test Client
@@ -357,9 +357,31 @@ The following is a simple unit test using the Test Client::
# Check that the rendered context contains 5 customers
self.failUnlessEqual(len(response.context['customers']), 5)
+Normal python unit tests extend a base class of ``unittest.testCase``.
+Django provides an extension of this base class - ``django.test.TestCase``
+- that provides some additional capabilities that can be useful for
+testing web sites.
+Moving from a normal unittest TestCase to a Django TestCase is easy - just
+change the base class of your test from ``unittest.TestCase`` to
+``django.test.TestCase``. All of the standard Python unit test facilities
+will continue to be available, but they will be augmented with some useful
+extra facilities.
+Default Test Client
+** New in Django development version **
+Every test case in a ``django.test.TestCase`` instance has access to an
+instance of a Django `Test Client`_. This Client can be accessed as
+``self.client``. This client is recreated for each test.
+Fixture loading
A test case for a database-backed website isn't much use if there isn't any
data in the database. To make it easy to put test data into the database,
Django provides a fixtures framework.
@@ -376,16 +398,14 @@ multiple applications.
This provides a mechanism to populate a new database with any initial
data (such as a default set of categories). Fixtures with other names
can be installed manually using `` loaddata``.
However, for the purposes of unit testing, each test must be able to
guarantee the contents of the database at the start of each and every
-test. To do this, Django provides a TestCase baseclass that can integrate
-with fixtures.
-Moving from a normal unittest TestCase to a Django TestCase is easy - just
-change the base class of your test, and define a list of fixtures
-to be used. For example, the test case from `Writing unittests`_ would
+To define a fixture for a test, all you need to do is add a class
+attribute to your test describing the fixtures you want the test to use.
+For example, the test case from `Writing unittests`_ would
look like::
from django.test import TestCase
@@ -410,6 +430,24 @@ This flush/load procedure is repeated for each test in the test case, so you
can be certain that the outcome of a test will not be affected by
another test, or the order of test execution.
+** New in Django development version **
+Normal Python unit tests have a wide range of assertions, such as
+``assertTrue`` and ``assertEquals`` that can be used to validate behavior.
+``django.TestCase`` adds to these, providing some assertions
+that can be useful in testing the behavior of web sites.
+``assertRedirects(response, expected_path)``
+ Assert that the response received redirects the browser to the provided
+ path, and that the expected_path can be retrieved.
+``assertContains(response, text, count=1)``
+ Assert that a response indicates that a page was retreived successfully,
+ (i.e., the HTTP status code was 200), and that ``text`` occurs ``count``
+ times in the content of the response.
Running tests
@@ -24,19 +24,14 @@
class ClientTest(TestCase):
fixtures = ['testdata.json']
- def setUp(self):
- "Set up test environment"
- self.client = Client()
def test_get_view(self):
"GET a view"
response = self.client.get('/test_client/get_view/')
# Check some response details
- self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'This is a test')
self.assertEqual(response.context['var'], 42)
self.assertEqual(, 'GET Template')
- self.failUnless('This is a test.' in response.content)
def test_get_post_view(self):
"GET a view that normally expects POSTs"
@@ -80,7 +75,7 @@ def test_redirect(self):
response = self.client.get('/test_client/redirect_view/')
# Check that the response was a 302 (redirect)
- self.assertEqual(response.status_code, 302)
+ self.assertRedirects(response, '/test_client/get_view/')
def test_valid_form(self):
"POST valid data to a form"
@@ -102,7 +97,7 @@ def test_incomplete_data_form(self):
'value': 37
response ='/test_client/form_view/', post_data)
- self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'This field is required', 3)
self.assertEqual(, "Invalid POST Template")
def test_form_error(self):
@@ -130,7 +125,7 @@ def test_view_with_login(self):
# Get the page without logging in. Should result in 302.
response = self.client.get('/test_client/login_protected_view/')
- self.assertEqual(response.status_code, 302)
+ self.assertRedirects(response, '/accounts/login/')
# Request a page that requires a login
response = self.client.login('/test_client/login_protected_view/', 'testclient', 'password')

0 comments on commit a0ef3ba

Please sign in to comment.