A few fixes for the testing documentation:

* Removed an extra semicolon that was preventing the rendering of a Sphinx class directive for the `Client()` class.
 * Indented `Client` class's methods.
 * Added linebreaks after attribute directives of `Response` class so Sphinx rendenders them correctly.
 * Removed trailing whitespace.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@8567 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Gary Wilson Jr 2008-08-26 00:52:55 +00:00
parent 5485e0d97f
commit b2c2c3a2ed
1 changed files with 191 additions and 181 deletions

View File

@ -131,21 +131,20 @@ Here is an example model doctest::
def speak(self): def speak(self):
return 'The %s says "%s"' % (self.name, self.sound) return 'The %s says "%s"' % (self.name, self.sound)
When you :ref:`run your tests <running-tests>`, the test runner will find this docstring, notice When you :ref:`run your tests <running-tests>`, the test runner will find this
that portions of it look like an interactive Python session, and execute those docstring, notice that portions of it look like an interactive Python session,
lines while checking that the results match. and execute those lines while checking that the results match.
In the case of model tests, note that the test runner takes care of In the case of model tests, note that the test runner takes care of creating
creating its own test database. That is, any test that accesses a its own test database. That is, any test that accesses a database -- by
database -- by creating and saving model instances, for example -- creating and saving model instances, for example -- will not affect your
will not affect your production database. Each doctest begins with a production database. Each doctest begins with a "blank slate" -- a fresh
"blank slate" -- a fresh database containing an empty table for each database containing an empty table for each model. (See the section on
model. (See the section on fixtures, below, for more on this.) Note fixtures, below, for more on this.) Note that to use this feature, the database
that to use this feature, the database user Django is connecting as user Django is connecting as must have ``CREATE DATABASE`` rights.
must have ``CREATE DATABASE`` rights.
For more details about how doctest works, see the `standard library For more details about how doctest works, see the `standard library
documentation for doctest`_ documentation for doctest`_.
.. _doctest: http://docs.python.org/lib/module-doctest.html .. _doctest: http://docs.python.org/lib/module-doctest.html
.. _standard library documentation for doctest: doctest_ .. _standard library documentation for doctest: doctest_
@ -182,17 +181,17 @@ in the doctest section above::
self.assertEquals(self.lion.speak(), 'The lion says "roar"') self.assertEquals(self.lion.speak(), 'The lion says "roar"')
self.assertEquals(self.cat.speak(), 'The cat says "meow"') self.assertEquals(self.cat.speak(), 'The cat says "meow"')
When you :ref:`run your tests <running-tests>`, the default behavior of the test utility is When you :ref:`run your tests <running-tests>`, the default behavior of the
to find all the test cases (that is, subclasses of ``unittest.TestCase``) test utility is to find all the test cases (that is, subclasses of
in ``models.py`` and ``tests.py``, automatically build a test suite out of ``unittest.TestCase``) in ``models.py`` and ``tests.py``, automatically build a
those test cases, and run that suite. test suite out of those test cases, and run that suite.
In the Django development version, there is a second way to define the test In the Django development version, there is a second way to define the test
suite for a module: if you define a function called ``suite()`` in either suite for a module: if you define a function called ``suite()`` in either
``models.py`` or ``tests.py``, the Django test runner will use that function ``models.py`` or ``tests.py``, the Django test runner will use that function
to construct the test suite for that module. This follows the to construct the test suite for that module. This follows the `suggested
`suggested organization`_ for unit tests. See the Python documentation for organization`_ for unit tests. See the Python documentation for more details on
more details on how to construct a complex test suite. how to construct a complex test suite.
For more details about ``unittest``, see the `standard library unittest For more details about ``unittest``, see the `standard library unittest
documentation`_. documentation`_.
@ -242,7 +241,8 @@ in different circumstances.
Running tests Running tests
============= =============
Once you've written tests, run them using your project's ``manage.py`` utility:: Once you've written tests, run them using your project's ``manage.py``
utility::
$ ./manage.py test $ ./manage.py test
@ -273,18 +273,18 @@ a test case, add the name of the test method to the label::
The test database The test database
----------------- -----------------
Tests that require a database (namely, model tests) will not use Tests that require a database (namely, model tests) will not use your "real"
your "real" (production) database. A separate, blank database is created (production) database. A separate, blank database is created for the tests.
for the tests.
Regardless of whether the tests pass or fail, the test database is destroyed Regardless of whether the tests pass or fail, the test database is destroyed
when all the tests have been executed. when all the tests have been executed.
By default this test database gets its name by prepending ``test_`` to the value By default this test database gets its name by prepending ``test_`` to the
of the :setting:`DATABASE_NAME` setting. When using the SQLite database engine value of the :setting:`DATABASE_NAME` setting. When using the SQLite database
the tests will by default use an in-memory database (i.e., the database will be engine the tests will by default use an in-memory database (i.e., the database
created in memory, bypassing the filesystem entirely!). If you want to use a will be created in memory, bypassing the filesystem entirely!). If you want to
different database name, specify the :setting:`TEST_DATABASE_NAME` setting. use a different database name, specify the :setting:`TEST_DATABASE_NAME`
setting.
Aside from using a separate database, the test runner will otherwise use all of Aside from using a separate database, the test runner will otherwise use all of
the same database settings you have in your settings file: the same database settings you have in your settings file:
@ -466,11 +466,12 @@ Making requests
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
Use the ``django.test.client.Client`` class to make requests. It requires no Use the ``django.test.client.Client`` class to make requests. It requires no
arguments at time of construction:: arguments at time of construction:
.. class:: Client() .. class:: Client()
Once you have a ``Client`` instance, you can call any of the following methods: Once you have a ``Client`` instance, you can call any of the following
methods:
.. method:: Client.get(path, data={}) .. method:: Client.get(path, data={})
@ -489,8 +490,8 @@ Once you have a ``Client`` instance, you can call any of the following methods:
.. method:: Client.post(path, data={}, content_type=MULTIPART_CONTENT) .. method:: Client.post(path, data={}, content_type=MULTIPART_CONTENT)
Makes a POST request on the provided ``path`` and returns a ``Response`` Makes a POST request on the provided ``path`` and returns a
object, which is documented below. ``Response`` object, which is documented below.
The key-value pairs in the ``data`` dictionary are used to submit POST The key-value pairs in the ``data`` dictionary are used to submit POST
data. For example:: data. For example::
@ -506,14 +507,15 @@ Once you have a ``Client`` instance, you can call any of the following methods:
name=fred&passwd=secret name=fred&passwd=secret
If you provide ``content_type`` (e.g., ``text/xml`` for an XML payload), If you provide ``content_type`` (e.g., ``text/xml`` for an XML
the contents of ``data`` will be sent as-is in the POST request, using payload), the contents of ``data`` will be sent as-is in the POST
``content_type`` in the HTTP ``Content-Type`` header. request, using ``content_type`` in the HTTP ``Content-Type`` header.
If you don't provide a value for ``content_type``, the values in If you don't provide a value for ``content_type``, the values in
``data`` will be transmitted with a content type of ``multipart/form-data``. ``data`` will be transmitted with a content type of
In this case, the key-value pairs in ``data`` will be encoded as a ``multipart/form-data``. In this case, the key-value pairs in ``data``
multipart message and used to create the POST data payload. will be encoded as a multipart message and used to create the POST data
payload.
To submit multiple values for a given key -- for example, to specify To submit multiple values for a given key -- for example, to specify
the selections for a ``<select multiple>`` -- provide the values as a the selections for a ``<select multiple>`` -- provide the values as a
@ -522,9 +524,9 @@ Once you have a ``Client`` instance, you can call any of the following methods:
{'choices': ('a', 'b', 'd')} {'choices': ('a', 'b', 'd')}
Submitting files is a special case. To POST a file, you need only provide Submitting files is a special case. To POST a file, you need only
the file field name as a key, and a file handle to the file you wish to provide the file field name as a key, and a file handle to the file you
upload as a value. For example:: wish to upload as a value. For example::
>>> c = Client() >>> c = Client()
>>> f = open('wishlist.doc') >>> f = open('wishlist.doc')
@ -534,58 +536,60 @@ Once you have a ``Client`` instance, you can call any of the following methods:
(The name ``attachment`` here is not relevant; use whatever name your (The name ``attachment`` here is not relevant; use whatever name your
file-processing code expects.) file-processing code expects.)
Note that you should manually close the file after it has been provided to Note that you should manually close the file after it has been provided
``post()``. to ``post()``.
.. method:: Client.login(**credentials) .. method:: Client.login(**credentials)
**New in Django development version** **New in Django development version**
If your site uses Django's :ref:`authentication system<topics-auth>` and you deal with If your site uses Django's :ref:`authentication system<topics-auth>`
logging in users, you can use the test client's ``login()`` method to and you deal with logging in users, you can use the test client's
simulate the effect of a user logging into the site. ``login()`` method to simulate the effect of a user logging into the
site.
After you call this method, the test client will have all the cookies and After you call this method, the test client will have all the cookies
session data required to pass any login-based tests that may form part of and session data required to pass any login-based tests that may form
a view. part of a view.
The format of the ``credentials`` argument depends on which The format of the ``credentials`` argument depends on which
:ref:`authentication backend <authentication-backends>` you're using (which is configured by your :ref:`authentication backend <authentication-backends>` you're using
:setting:`AUTHENTICATION_BACKENDS` setting). If you're using the standard (which is configured by your :setting:`AUTHENTICATION_BACKENDS`
authentication backend provided by Django (``ModelBackend``), setting). If you're using the standard authentication backend provided
``credentials`` should be the user's username and password, provided as by Django (``ModelBackend``), ``credentials`` should be the user's
keyword arguments:: username and password, provided as keyword arguments::
>>> c = Client() >>> c = Client()
>>> c.login(username='fred', password='secret') >>> c.login(username='fred', password='secret')
# Now you can access a view that's only available to logged-in users. # Now you can access a view that's only available to logged-in users.
If you're using a different authentication backend, this method may require If you're using a different authentication backend, this method may
different credentials. It requires whichever credentials are required by require different credentials. It requires whichever credentials are
your backend's ``authenticate()`` method. required by your backend's ``authenticate()`` method.
``login()`` returns ``True`` if it the credentials were accepted and login ``login()`` returns ``True`` if it the credentials were accepted and
was successful. login was successful.
Finally, you'll need to remember to create user accounts before you can use Finally, you'll need to remember to create user accounts before you can
this method. As we explained above, the test runner is executed using a use this method. As we explained above, the test runner is executed
test database, which contains no users by default. As a result, user using a test database, which contains no users by default. As a result,
accounts that are valid on your production site will not work under test user accounts that are valid on your production site will not work
conditions. You'll need to create users as part of the test suite -- either under test conditions. You'll need to create users as part of the test
manually (using the Django model API) or with a test fixture. suite -- either manually (using the Django model API) or with a test
fixture.
.. method:: Client.logout() .. method:: Client.logout()
**New in Django development version** **New in Django development version**
If your site uses Django's :ref:`authentication system<topics-auth>`, the ``logout()`` If your site uses Django's :ref:`authentication system<topics-auth>`,
method can be used to simulate the effect of a user logging out of the ``logout()`` method can be used to simulate the effect of a user
your site. logging out of your site.
After you call this method, the test client will have all the cookies and After you call this method, the test client will have all the cookies
session data cleared to defaults. Subsequent requests will appear to and session data cleared to defaults. Subsequent requests will appear
come from an AnonymousUser. to come from an AnonymousUser.
Testing responses Testing responses
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
@ -599,36 +603,42 @@ Specifically, a ``Response`` object has the following attributes:
.. class:: Response() .. class:: Response()
.. attribute:: Response.client`` .. attribute:: client
The test client that was used to make the request that resulted in the The test client that was used to make the request that resulted in the
response. response.
.. attribute:: Response.content .. attribute:: content
The body of the response, as a string. This is the final page content as The body of the response, as a string. This is the final page content as
rendered by the view, or any error message. rendered by the view, or any error message.
.. attribute:: Response.context .. attribute:: context
The template ``Context`` instance that was used to render the template that The template ``Context`` instance that was used to render the template that
produced the response content. produced the response content.
If the rendered page used multiple templates, then ``context`` will be a If the rendered page used multiple templates, then ``context`` will be a
list of ``Context`` objects, in the order in which they were rendered. list of ``Context`` objects, in the order in which they were rendered.
.. attribute:: Response.request`` .. attribute:: request
The request data that stimulated the response. The request data that stimulated the response.
.. attribute:: Response.status_code .. attribute:: status_code
The HTTP status of the response, as an integer. See RFC2616_ for a full list
of HTTP status codes. The HTTP status of the response, as an integer. See RFC2616_ for a full
list of HTTP status codes.
.. attribute:: template .. attribute:: template
The ``Template`` instance that was used to render the final content. Use The ``Template`` instance that was used to render the final content. Use
``template.name`` to get the template's file name, if the template was ``template.name`` to get the template's file name, if the template was
loaded from a file. (The name is a string such as ``'admin/index.html'``.) loaded from a file. (The name is a string such as ``'admin/index.html'``.)
If the rendered page used multiple templates -- e.g., using :ref:`template If the rendered page used multiple templates -- e.g., using :ref:`template
inheritance<template-inheritance>` -- then ``template`` will be a list of ``Template`` instances, inheritance<template-inheritance>` -- then ``template`` will be a list of
in the order in which they were rendered. ``Template`` instances, in the order in which they were rendered.
You can also use dictionary syntax on the response object to query the value You can also use dictionary syntax on the response object to query the value
of any settings in the HTTP headers. For example, you could determine the of any settings in the HTTP headers. For example, you could determine the
@ -669,8 +679,8 @@ can access these properties as part of a test condition.
.. attribute:: Client.session .. attribute:: Client.session
A dictionary-like object containing session information. See the :ref:`session A dictionary-like object containing session information. See the
documentation<topics-http-sessions>` for full details. :ref:`session documentation<topics-http-sessions>` for full details.
.. _Cookie module documentation: http://docs.python.org/lib/module-Cookie.html .. _Cookie module documentation: http://docs.python.org/lib/module-Cookie.html
@ -772,9 +782,9 @@ A fixture is a collection of data that Django knows how to import into a
database. For example, if your site has user accounts, you might set up a database. For example, if your site has user accounts, you might set up a
fixture of fake user accounts in order to populate your database during tests. fixture of fake user accounts in order to populate your database during tests.
The most straightforward way of creating a fixture is to use the The most straightforward way of creating a fixture is to use the ``manage.py
``manage.py dumpdata`` command. This assumes you already have some data in dumpdata`` command. This assumes you already have some data in your database.
your database. See the :djadmin:`dumpdata documentation<dumpdata>` for more details. See the :djadmin:`dumpdata documentation<dumpdata>` for more details.
.. note:: .. note::
If you've ever run ``manage.py syncdb``, you've already used a fixture If you've ever run ``manage.py syncdb``, you've already used a fixture
@ -810,12 +820,12 @@ Here's specifically what will happen:
* Then, all the named fixtures are installed. In this example, Django will * Then, all the named fixtures are installed. In this example, Django will
install any JSON fixture named ``mammals``, followed by any fixture named install any JSON fixture named ``mammals``, followed by any fixture named
``birds``. See the :djadmin:`loaddata documentation<loaddata>` for more details on defining ``birds``. See the :djadmin:`loaddata documentation<loaddata>` for more
and installing fixtures. details on defining and installing fixtures.
This flush/load procedure is repeated for each test in the test case, so you 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,
another test, or by the order of test execution. or by the order of test execution.
URLconf configuration URLconf configuration
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
@ -824,18 +834,18 @@ URLconf configuration
.. attribute:: TestCase.urls .. attribute:: TestCase.urls
If your application provides views, you may want to include tests that If your application provides views, you may want to include tests that use the
use the test client to exercise those views. However, an end user is free test client to exercise those views. However, an end user is free to deploy the
to deploy the views in your application at any URL of their choosing. views in your application at any URL of their choosing. This means that your
This means that your tests can't rely upon the fact that your views will tests can't rely upon the fact that your views will be available at a
be available at a particular URL. particular URL.
In order to provide a reliable URL space for your test, In order to provide a reliable URL space for your test,
``django.test.TestCase`` provides the ability to customize the URLconf ``django.test.TestCase`` provides the ability to customize the URLconf
configuration for the duration of the execution of a test suite. configuration for the duration of the execution of a test suite. If your
If your ``TestCase`` instance defines an ``urls`` attribute, the ``TestCase`` instance defines an ``urls`` attribute, the ``TestCase`` will use
``TestCase`` will use the value of that attribute as the ``ROOT_URLCONF`` the value of that attribute as the ``ROOT_URLCONF`` for the duration of that
for the duration of that test. test.
For example:: For example::
@ -867,10 +877,10 @@ Assertions
**New in Django development version** **New in Django development version**
As Python's normal ``unittest.TestCase`` class implements assertion As Python's normal ``unittest.TestCase`` class implements assertion methods
methods such as ``assertTrue`` and ``assertEquals``, Django's custom such as ``assertTrue`` and ``assertEquals``, Django's custom ``TestCase`` class
``TestCase`` class provides a number of custom assertion methods that are provides a number of custom assertion methods that are useful for testing Web
useful for testing Web applications: applications:
.. method:: TestCase.assertContains(response, text, count=None, status_code=200) .. method:: TestCase.assertContains(response, text, count=None, status_code=200)
@ -913,8 +923,8 @@ useful for testing Web applications:
.. method:: assertRedirects(response, expected_url, status_code=302, target_status_code=200) .. method:: assertRedirects(response, expected_url, status_code=302, target_status_code=200)
Asserts that the response return a ``status_code`` redirect status, Asserts that the response return a ``status_code`` redirect status, it
it redirected to ``expected_url`` (including any GET data), and the subsequent redirected to ``expected_url`` (including any GET data), and the subsequent
page was received with ``target_status_code``. page was received with ``target_status_code``.
E-mail services E-mail services
@ -930,21 +940,22 @@ test every aspect of sending e-mail -- from the number of messages sent to the
contents of each message -- without actually sending the messages. contents of each message -- without actually sending the messages.
The test runner accomplishes this by transparently replacing the normal The test runner accomplishes this by transparently replacing the normal
:class:`~django.core.mail.SMTPConnection` class with a different version. (Don't :class:`~django.core.mail.SMTPConnection` class with a different version.
worry -- this has no effect on any other e-mail senders outside of Django, such (Don't worry -- this has no effect on any other e-mail senders outside of
as your machine's mail server, if you're running one.) Django, such as your machine's mail server, if you're running one.)
.. currentmodule:: django.core.mail .. currentmodule:: django.core.mail
.. data:: django.core.mail.output .. data:: django.core.mail.output
During test running, each outgoing e-mail is saved in During test running, each outgoing e-mail is saved in
``django.core.mail.outbox``. This is a simple list of all :class:`<~django.core.mail.EmailMessage>` ``django.core.mail.outbox``. This is a simple list of all
instances that have been sent. It does not exist under normal execution :class:`<~django.core.mail.EmailMessage>` instances that have been sent.
conditions, i.e., when you're not running unit tests. The outbox is created It does not exist under normal execution conditions, i.e., when you're not
during test setup, along with the dummy :class:`<~django.core.mail.SMTPConnection>`. When the test running unit tests. The outbox is created during test setup, along with the
framework is torn down, the standard :class:`<~django.core.mail.SMTPConnection>` class is restored, and dummy :class:`<~django.core.mail.SMTPConnection>`. When the test framework is
the test outbox is destroyed. torn down, the standard :class:`<~django.core.mail.SMTPConnection>` class is
restored, and the test outbox is destroyed.
Here's an example test that examines ``django.core.mail.outbox`` for length Here's an example test that examines ``django.core.mail.outbox`` for length
and contents:: and contents::
@ -965,9 +976,9 @@ and contents::
# Verify that the subject of the first message is correct. # Verify that the subject of the first message is correct.
self.assertEqual(mail.outbox[0].subject, 'Subject here') self.assertEqual(mail.outbox[0].subject, 'Subject here')
As noted :ref:`previously <emptying-test-outbox>`, the test outbox is emptied at the start of every As noted :ref:`previously <emptying-test-outbox>`, the test outbox is emptied
test in a Django ``TestCase``. To empty the outbox manually, assign the at the start of every test in a Django ``TestCase``. To empty the outbox
empty list to ``mail.outbox``:: manually, assign the empty list to ``mail.outbox``::
from django.core import mail from django.core import mail
@ -1004,9 +1015,9 @@ testing behavior. This behavior involves:
#. Performing global post-test teardown. #. Performing global post-test teardown.
If you define your own test runner method and point :setting:`TEST_RUNNER` at If you define your own test runner method and point :setting:`TEST_RUNNER` at
that method, Django will execute your test runner whenever you run ``./manage.py that method, Django will execute your test runner whenever you run
test``. In this way, it is possible to use any test framework that can be ``./manage.py test``. In this way, it is possible to use any test framework
executed from Python code. that can be executed from Python code.
Defining a test runner Defining a test runner
---------------------- ----------------------
@ -1053,20 +1064,19 @@ Testing utilities
.. module:: django.test.utils .. module:: django.test.utils
:synopsis: Helpers to write custom test runners. :synopsis: Helpers to write custom test runners.
To assist in the creation of your own test runner, Django provides To assist in the creation of your own test runner, Django provides a number of
a number of utility methods in the ``django.test.utils`` module. utility methods in the ``django.test.utils`` module.
.. function:: setup_test_environment() .. function:: setup_test_environment()
Performs any global pre-test setup, such as the installing the Performs any global pre-test setup, such as the installing the
instrumentation of the template rendering system and setting up instrumentation of the template rendering system and setting up the dummy
the dummy ``SMTPConnection``. ``SMTPConnection``.
.. function:: teardown_test_environment() .. function:: teardown_test_environment()
Performs any global post-test teardown, such as removing the Performs any global post-test teardown, such as removing the black magic
black magic hooks into the template system and restoring normal e-mail hooks into the template system and restoring normal e-mail services.
services.
The creation module of the database backend (``connection.creation``) also The creation module of the database backend (``connection.creation``) also
provides some utilities that can be useful during testing. provides some utilities that can be useful during testing.