From 8192a808bdb70752fc30a329a282e9c3e95850a8 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee 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.