From 8192a808bdb70752fc30a329a282e9c3e95850a8 Mon Sep 17 00:00:00 2001
From: Russell Keith-Magee <russell@keith-magee.com>
Date: Sun, 3 Sep 2006 02:44:15 +0000
Subject: [PATCH] Refs #2333 - Added documentation for the test Client, and
 removed a stray import.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@3711 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 django/template/__init__.py |   1 -
 docs/testing.txt            | 203 +++++++++++++++++++++++++++++++-----
 2 files changed, 179 insertions(+), 25 deletions(-)

diff --git a/django/template/__init__.py b/django/template/__init__.py
index d49952afed..faf31c1e46 100644
--- a/django/template/__init__.py
+++ b/django/template/__init__.py
@@ -60,7 +60,6 @@ from django.conf import settings
 from django.template.context import Context, RequestContext, ContextPopException
 from django.utils.functional import curry
 from django.utils.text import smart_split
-from django.dispatch import dispatcher
 
 __all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
 
diff --git a/docs/testing.txt b/docs/testing.txt
index 98ed1e8aec..482148f59a 100644
--- a/docs/testing.txt
+++ b/docs/testing.txt
@@ -159,20 +159,166 @@ Again, remember that you can use both systems side-by-side (even in the same
 app). In the end, most projects will eventually end up using both; each shines
 in different circumstances.
 
-Testing utilities
-=================
+Testing Tools
+=============
 
+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_
+  
 Test Client
 -----------
 
-A dummy browser; instruments the template generation process...
+The Test Client is a simple dummy browser. It allows you to simulate
+GET and POST requests on a URL, and observe the response that is received.
+This allows you to test that the correct view is executed for a given URL,
+and that the view constructs the correct response.
+
+As the response is generated, the Test Client gathers details on the 
+Template and Context objects that were used to generate the response. These
+Templates and Contexts are then provided as part of the response, and can be
+used as test conditions.
+
+.. admonition:: Test Client vs Browser Automation?
+
+    The Test Client is not intended as a replacement for Twill_, Selenium_, 
+    or other browser automation frameworks - it is intended to allow 
+    testing of the contexts and templates produced by a view, 
+    rather than the HTML rendered to the end-user.
+    
+    A comprehensive test suite should use a combination of both: Test Client
+    tests to establish that the correct view is being called and that 
+    the view is collecting the correct context data, and Browser Automation
+    tests to check that user interface behaves as expected.
+    
+.. _Twill: http://twill.idyll.org/
+.. _Selenium: http://www.openqa.org/selenium/
+
+The Test Client is stateful; if a cookie is returned as part of a response,
+that cookie is provided as part of the next request. Expiry policies for these
+cookies are not followed; if you want a cookie to expire, either delete it 
+manually from ``client.cookies``, or create a new Client instance (which will
+effectively delete all cookies).
+
+Making requests
+~~~~~~~~~~~~~~~
+
+Creating an instance of ``Client`` (``django.test.client.Client``) requires 
+no arguments at time of construction. Once constructed, the following methods
+can be invoked on the ``Client`` instance.
+
+``get(path, data={}):``
+
+    Make a GET request on the provided ``path``. The key-value pairs in the
+    data dictionary will be used to create a GET data payload. For example::
+
+        c = Client()
+        c.get('/customers/details/', {'name':'fred', 'age':7})
+
+    will result in the evaluation of a GET request equivalent to::
+
+        http://yoursite.com/customers/details/?name='fred'&age=7
+
+``post(path, data={}):``
+
+    Make a POST request on the provided ``path``. The key-value pairs in the
+    data dictionary will be used to create the POST data payload. This payload
+    will be transmitted with the mimetype ```multipart/form-data``. 
+
+    However submitting files is a special case. To POST a file, you need only
+    provide the file field name as a key, and a file handle to the file you wish to 
+    upload as a value. The Test Client will populate the two POST fields (i.e., 
+    ``field`` and ``field_file``) required by FileField. For example::
+
+        c = Client()
+        f = open('wishlist.doc')
+        c.post('/customers/wishes/', {'name':'fred', 'attachment':f})
+        f.close()
+
+    will result in the evaluation of a POST request on ``/customers/wishes/``, 
+    with a POST dictionary that contains `name`, `attachment` (containing the 
+    file name), and `attachment_file` (containing the file data). Note that you
+    need to manually close the file after it has been provided to the POST.
+
+``login(path, username, password):``
+
+    In a production site, it is likely that some views will be protected with
+    the @login_required URL provided by ``django.contrib.auth``. Interacting
+    with a URL that has been login protected is a slightly complex operation,
+    so the Test Client provides a simple URL to automate the login process. A
+    call to ``login()`` stimulates the series of GET and POST calls required
+    to log a user into a @login_required protected URL.
+
+    If login is possible, the final return value of ``login()`` is the response 
+    that is generated by issuing a GET request on the protected URL. If login
+    is not possible, ``login()`` returns False.
+
+    Note that since the test suite will be executed using the test database, 
+    which contains no users by default. As a result, logins for your production
+    site will not work. You will need to create users as part of the test suite 
+    to be able to test logins to your application. 
+
+Testing Responses
+~~~~~~~~~~~~~~~~~
+
+The ``get()``, ``post()`` and ``login()`` methods all return a Response 
+object. This Response object has the following properties that can be used 
+for testing purposes:
+
+``status_code``
+
+    The HTTP status of the response. See RFC2616_ for a full list of HTTP status 
+    codes.
+
+    .. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+
+``content``
+
+    The body of the response. The is the final page content as rendered by 
+    the view, or any error message (such as the URL for a 302 redirect).
+
+``template``
+
+    The Template instance that was used to render the final content. 
+    Testing ``template.name`` can be particularly useful; if the 
+    template was loaded from a file, ``name`` will be the file name that 
+    was loaded. 
+
+    If multiple templates were rendered, (e.g., if one template includes 
+    another template),``template`` will be a list of Template objects, in 
+    the order in which they were rendered.
+
+``context``
+
+    The Context that was used to render the template that produced the 
+    response content.
+
+    As with ``template``, if multiple templates were rendered ``context`` 
+    will be a list of Context objects, stored in the order in which they 
+    were rendered. 
+
+The following is a simple unit test using the Test Client::
+    
+    import unittest
+    from django.test.client import Client
+    
+    class SimpleTest(unittest.TestCase):
+        def setUp(self):
+            # Every test needs a client
+            self.client = Client()
+        def test_details(self):        
+            response = self.client.get('/customer/details/')
+    
+            self.failUnlessEqual(response.status_code, 200)
+            self.failUnlessEqual(len(response.context['customers']), 5)
 
 Fixtures
 --------
 
 Feature still to come...
 
-
 Running tests
 =============
 
@@ -245,11 +391,13 @@ When you run ``./manage.py test``, Django looks at the ``TEST_RUNNER``
 setting to determine what to do. By default, ``TEST_RUNNER`` points to ``django.test.simple.run_tests``. This method defines the default Django
 testing behaviour. This behaviour involves:
 
+#. Performing global pre-test setup
 #. Creating the test database
 #. Running ``syncdb`` to install models and initial data into the test database
 #. Looking for Unit Tests and Doctests in ``models.py`` and ``tests.py`` file for each installed application
 #. Running the Unit Tests and Doctests that are found
 #. Destroying the test database.
+#. Performing global post-test teardown
 
 If you define your own test runner method and point ``TEST_RUNNER``
 at that method, Django will execute your test runner whenever you run
@@ -263,14 +411,13 @@ can call it anything you want. The only requirement is that it accept two
 arguments:
 
 ``run_tests(module_list, verbosity=1)``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-The module list is the list of Python modules that contain the models to be
-tested. This is the same format returned by ``django.db.models.get_apps()``
+    The module list is the list of Python modules that contain the models to be
+    tested. This is the same format returned by ``django.db.models.get_apps()``
 
-Verbosity determines the amount of notification and debug information that 
-will be printed to the console; '0' is no output, '1' is normal output,
-and `2` is verbose output.
+    Verbosity determines the amount of notification and debug information that 
+    will be printed to the console; '0' is no output, '1' is normal output,
+    and `2` is verbose output.
 
 Testing utilities
 -----------------
@@ -278,26 +425,34 @@ Testing utilities
 To assist in the creation of your own test runner, Django provides
 a number of utility methods in the ``django.test.utils`` module.
 
+``setup_test_environment()``
+
+    Performs any global pre-test setup, such as the installing the 
+    instrumentation of the template rendering system. 
+
+``teardown_test_environment()``
+
+    Performs any global post-test teardown, such as removing the instrumentation 
+    of the template rendering system. 
+
 ``create_test_db(verbosity=1, autoclobber=False)``:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Creates a new test database, and run ``syncdb`` against it.
+    Creates a new test database, and run ``syncdb`` against it.
 
-``verbosity`` has the same behaviour as in the test runner.
+    ``verbosity`` has the same behaviour as in the test runner.
 
-``Autoclobber`` describes the behavior that will occur if a database with
-the same name as the test database is discovered. If ``autoclobber`` is False,
-the user will be asked to approve destroying the existing database. ``sys.exit``
-is called if the user does not approve. If autoclobber is ``True``, the database
-will be destroyed without consulting the user.
+    ``Autoclobber`` describes the behavior that will occur if a database with
+    the same name as the test database is discovered. If ``autoclobber`` is False,
+    the user will be asked to approve destroying the existing database. ``sys.exit``
+    is called if the user does not approve. If autoclobber is ``True``, the database
+    will be destroyed without consulting the user.
 
-``create_test_db()`` has the side effect of modifying
-``settings.DATABASE_NAME`` to match the name of the test database.
+    ``create_test_db()`` has the side effect of modifying
+    ``settings.DATABASE_NAME`` to match the name of the test database.
 
 ``destroy_test_db(old_database_name, verbosity=1)``:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Destroys the database with the name ``settings.DATABASE_NAME`` matching,
-and restores the value of ``settings.DATABASE_NAME`` to the provided name.
+    Destroys the database with the name ``settings.DATABASE_NAME`` matching,
+    and restores the value of ``settings.DATABASE_NAME`` to the provided name.
 
-``verbosity`` has the same behaviour as in the test runner.
+    ``verbosity`` has the same behaviour as in the test runner.