Added a default test Client to TestCase, and added some assertions for some common testing patterns.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5150 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
e986e8aba4
commit
a0ef3ba2f7
|
@ -1,8 +1,10 @@
|
||||||
import re, doctest, unittest
|
import re, doctest, unittest
|
||||||
|
from urlparse import urlparse
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.core import management
|
from django.core import management
|
||||||
from django.db.models import get_apps
|
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)
|
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
|
||||||
|
|
||||||
class OutputChecker(doctest.OutputChecker):
|
class OutputChecker(doctest.OutputChecker):
|
||||||
|
@ -46,5 +48,33 @@ class TestCase(unittest.TestCase):
|
||||||
super().
|
super().
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
self.client = Client()
|
||||||
self.install_fixtures()
|
self.install_fixtures()
|
||||||
super(TestCase, self).run(result)
|
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.
|
tools that can be used to establish tests and test conditions.
|
||||||
|
|
||||||
* `Test Client`_
|
* `Test Client`_
|
||||||
* Fixtures_
|
* `TestCase`_
|
||||||
|
|
||||||
Test Client
|
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
|
# Check that the rendered context contains 5 customers
|
||||||
self.failUnlessEqual(len(response.context['customers']), 5)
|
self.failUnlessEqual(len(response.context['customers']), 5)
|
||||||
|
|
||||||
Fixtures
|
TestCase
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
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
|
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,
|
data in the database. To make it easy to put test data into the database,
|
||||||
Django provides a fixtures framework.
|
Django provides a fixtures framework.
|
||||||
|
@ -376,16 +398,14 @@ multiple applications.
|
||||||
This provides a mechanism to populate a new database with any initial
|
This provides a mechanism to populate a new database with any initial
|
||||||
data (such as a default set of categories). Fixtures with other names
|
data (such as a default set of categories). Fixtures with other names
|
||||||
can be installed manually using ``django-admin.py loaddata``.
|
can be installed manually using ``django-admin.py loaddata``.
|
||||||
|
|
||||||
|
|
||||||
However, for the purposes of unit testing, each test must be able to
|
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
|
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
|
test.
|
||||||
with fixtures.
|
|
||||||
|
|
||||||
Moving from a normal unittest TestCase to a Django TestCase is easy - just
|
To define a fixture for a test, all you need to do is add a class
|
||||||
change the base class of your test, and define a list of fixtures
|
attribute to your test describing the fixtures you want the test to use.
|
||||||
to be used. For example, the test case from `Writing unittests`_ would
|
For example, the test case from `Writing unittests`_ would
|
||||||
look like::
|
look like::
|
||||||
|
|
||||||
from django.test import TestCase
|
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
|
can be certain that the outcome of a test will not be affected by
|
||||||
another test, or the order of test execution.
|
another test, or the order of test execution.
|
||||||
|
|
||||||
|
Assertions
|
||||||
|
~~~~~~~~~~
|
||||||
|
** 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
|
Running tests
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -24,19 +24,14 @@ from django.test import Client, TestCase
|
||||||
class ClientTest(TestCase):
|
class ClientTest(TestCase):
|
||||||
fixtures = ['testdata.json']
|
fixtures = ['testdata.json']
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
"Set up test environment"
|
|
||||||
self.client = Client()
|
|
||||||
|
|
||||||
def test_get_view(self):
|
def test_get_view(self):
|
||||||
"GET a view"
|
"GET a view"
|
||||||
response = self.client.get('/test_client/get_view/')
|
response = self.client.get('/test_client/get_view/')
|
||||||
|
|
||||||
# Check some response details
|
# 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(response.context['var'], 42)
|
||||||
self.assertEqual(response.template.name, 'GET Template')
|
self.assertEqual(response.template.name, 'GET Template')
|
||||||
self.failUnless('This is a test.' in response.content)
|
|
||||||
|
|
||||||
def test_get_post_view(self):
|
def test_get_post_view(self):
|
||||||
"GET a view that normally expects POSTs"
|
"GET a view that normally expects POSTs"
|
||||||
|
@ -80,7 +75,7 @@ class ClientTest(TestCase):
|
||||||
response = self.client.get('/test_client/redirect_view/')
|
response = self.client.get('/test_client/redirect_view/')
|
||||||
|
|
||||||
# Check that the response was a 302 (redirect)
|
# 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):
|
def test_valid_form(self):
|
||||||
"POST valid data to a form"
|
"POST valid data to a form"
|
||||||
|
@ -102,7 +97,7 @@ class ClientTest(TestCase):
|
||||||
'value': 37
|
'value': 37
|
||||||
}
|
}
|
||||||
response = self.client.post('/test_client/form_view/', post_data)
|
response = self.client.post('/test_client/form_view/', post_data)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertContains(response, 'This field is required', 3)
|
||||||
self.assertEqual(response.template.name, "Invalid POST Template")
|
self.assertEqual(response.template.name, "Invalid POST Template")
|
||||||
|
|
||||||
def test_form_error(self):
|
def test_form_error(self):
|
||||||
|
@ -130,7 +125,7 @@ class ClientTest(TestCase):
|
||||||
|
|
||||||
# Get the page without logging in. Should result in 302.
|
# Get the page without logging in. Should result in 302.
|
||||||
response = self.client.get('/test_client/login_protected_view/')
|
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
|
# Request a page that requires a login
|
||||||
response = self.client.login('/test_client/login_protected_view/', 'testclient', 'password')
|
response = self.client.login('/test_client/login_protected_view/', 'testclient', 'password')
|
||||||
|
|
Loading…
Reference in New Issue