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
|
||||
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 @@ class TestCase(unittest.TestCase):
|
|||
super().
|
||||
|
||||
"""
|
||||
self.client = Client()
|
||||
self.install_fixtures()
|
||||
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)
|
||||
|
||||
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
|
||||
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 ``django-admin.py 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.
|
||||
test.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
=============
|
||||
|
||||
|
|
|
@ -24,19 +24,14 @@ from django.test import Client, TestCase
|
|||
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(response.template.name, '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 @@ class ClientTest(TestCase):
|
|||
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 @@ class ClientTest(TestCase):
|
|||
'value': 37
|
||||
}
|
||||
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")
|
||||
|
||||
def test_form_error(self):
|
||||
|
@ -130,7 +125,7 @@ class ClientTest(TestCase):
|
|||
|
||||
# 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')
|
||||
|
|
Loading…
Reference in New Issue