/docs/topics/testing.txt
Plain Text | 1801 lines | 1291 code | 510 blank | 0 comment | 0 complexity | 168acb74e07b0e612dca55e557f4fece MD5 | raw file
Possible License(s): BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- ===========================
- Testing Django applications
- ===========================
- .. module:: django.test
- :synopsis: Testing tools for Django applications.
- Automated testing is an extremely useful bug-killing tool for the modern
- Web developer. You can use a collection of tests -- a **test suite** -- to
- solve, or avoid, a number of problems:
- * When you're writing new code, you can use tests to validate your code
- works as expected.
- * When you're refactoring or modifying old code, you can use tests to
- ensure your changes haven't affected your application's behavior
- unexpectedly.
- Testing a Web application is a complex task, because a Web application is made
- of several layers of logic -- from HTTP-level request handling, to form
- validation and processing, to template rendering. With Django's test-execution
- framework and assorted utilities, you can simulate requests, insert test data,
- inspect your application's output and generally verify your code is doing what
- it should be doing.
- The best part is, it's really easy.
- This document is split into two primary sections. First, we explain how to
- write tests with Django. Then, we explain how to run them.
- Writing tests
- =============
- There are two primary ways to write tests with Django, corresponding to the
- two test frameworks that ship in the Python standard library. The two
- frameworks are:
- * **Unit tests** -- tests that are expressed as methods on a Python class
- that subclasses ``unittest.TestCase`` or Django's customized
- :class:`TestCase`. For example::
- import unittest
- class MyFuncTestCase(unittest.TestCase):
- def testBasic(self):
- a = ['larry', 'curly', 'moe']
- self.assertEqual(my_func(a, 0), 'larry')
- self.assertEqual(my_func(a, 1), 'curly')
- * **Doctests** -- tests that are embedded in your functions' docstrings and
- are written in a way that emulates a session of the Python interactive
- interpreter. For example::
- def my_func(a_list, idx):
- """
- >>> a = ['larry', 'curly', 'moe']
- >>> my_func(a, 0)
- 'larry'
- >>> my_func(a, 1)
- 'curly'
- """
- return a_list[idx]
- We'll discuss choosing the appropriate test framework later, however, most
- experienced developers prefer unit tests. You can also use any *other* Python
- test framework, as we'll explain in a bit.
- Writing unit tests
- ------------------
- Django's unit tests use a Python standard library module: unittest_. This
- module defines tests in class-based approach.
- .. admonition:: unittest2
- .. versionchanged:: 1.3
- Python 2.7 introduced some major changes to the unittest library,
- adding some extremely useful features. To ensure that every Django
- project can benefit from these new features, Django ships with a
- copy of unittest2_, a copy of the Python 2.7 unittest library,
- backported for Python 2.4 compatibility.
- To access this library, Django provides the
- ``django.utils.unittest`` module alias. If you are using Python
- 2.7, or you have installed unittest2 locally, Django will map the
- alias to the installed version of the unittest library. Otherwise,
- Django will use it's own bundled version of unittest2.
- To use this alias, simply use::
- from django.utils import unittest
- wherever you would have historically used::
- import unittest
- If you want to continue to use the base unittest library, you can --
- you just won't get any of the nice new unittest2 features.
- .. _unittest2: http://pypi.python.org/pypi/unittest2
- For a given Django application, the test runner looks for unit tests in two
- places:
- * The ``models.py`` file. The test runner looks for any subclass of
- ``unittest.TestCase`` in this module.
- * A file called ``tests.py`` in the application directory -- i.e., the
- directory that holds ``models.py``. Again, the test runner looks for any
- subclass of ``unittest.TestCase`` in this module.
- Here is an example ``unittest.TestCase`` subclass::
- from django.utils import unittest
- from myapp.models import Animal
- class AnimalTestCase(unittest.TestCase):
- def setUp(self):
- self.lion = Animal.objects.create(name="lion", sound="roar")
- self.cat = Animal.objects.create(name="cat", sound="meow")
- def testSpeaking(self):
- self.assertEqual(self.lion.speak(), 'The lion says "roar"')
- self.assertEqual(self.cat.speak(), 'The cat says "meow"')
- When you :ref:`run your tests <running-tests>`, the default behavior of the
- test utility is to find all the test cases (that is, subclasses of
- ``unittest.TestCase``) in ``models.py`` and ``tests.py``, automatically build a
- test suite out of those test cases, and run that suite.
- There is a second way to define the test 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 to construct the test suite for that
- module. This follows the `suggested organization`_ for unit tests. See the
- Python documentation for more details on how to construct a complex test
- suite.
- For more details about ``unittest``, see the `standard library unittest
- documentation`_.
- .. _unittest: http://docs.python.org/library/unittest.html
- .. _standard library unittest documentation: unittest_
- .. _suggested organization: http://docs.python.org/library/unittest.html#organizing-tests
- Writing doctests
- ----------------
- Doctests use Python's standard doctest_ module, which searches your docstrings
- for statements that resemble a session of the Python interactive interpreter.
- A full explanation of how doctest works is out of the scope of this document;
- read Python's official documentation for the details.
- .. admonition:: What's a **docstring**?
- A good explanation of docstrings (and some guidelines for using them
- effectively) can be found in :pep:`257`:
- A docstring is a string literal that occurs as the first statement in
- a module, function, class, or method definition. Such a docstring
- becomes the ``__doc__`` special attribute of that object.
- For example, this function has a docstring that describes what it does::
- def add_two(num):
- "Return the result of adding two to the provided number."
- return num + 2
- Because tests often make great documentation, putting tests directly in
- your docstrings is an effective way to document *and* test your code.
- As with unit tests, for a given Django application, the test runner looks for
- doctests in two places:
- * The ``models.py`` file. You can define module-level doctests and/or a
- doctest for individual models. It's common practice to put
- application-level doctests in the module docstring and model-level
- doctests in the model docstrings.
- * A file called ``tests.py`` in the application directory -- i.e., the
- directory that holds ``models.py``. This file is a hook for any and all
- doctests you want to write that aren't necessarily related to models.
- This example doctest is equivalent to the example given in the unittest section
- above::
- # models.py
- from django.db import models
- class Animal(models.Model):
- """
- An animal that knows how to make noise
- # Create some animals
- >>> lion = Animal.objects.create(name="lion", sound="roar")
- >>> cat = Animal.objects.create(name="cat", sound="meow")
- # Make 'em speak
- >>> lion.speak()
- 'The lion says "roar"'
- >>> cat.speak()
- 'The cat says "meow"'
- """
- name = models.CharField(max_length=20)
- sound = models.CharField(max_length=20)
- def speak(self):
- 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 that portions of it look like an interactive Python session,
- and execute those lines while checking that the results match.
- In the case of model tests, note that the test runner takes care of creating
- its own test database. That is, any test that accesses a database -- by
- creating and saving model instances, for example -- will not affect your
- production database. However, the database is not refreshed between doctests,
- so if your doctest requires a certain state you should consider flushing the
- database or loading a fixture. (See the section on fixtures, below, for more
- on this.) Note that to use this feature, the database user Django is connecting
- as must have ``CREATE DATABASE`` rights.
- For more details about how doctest works, see the `standard library
- documentation for doctest`_.
- .. _doctest: http://docs.python.org/library/doctest.html
- .. _standard library documentation for doctest: doctest_
- Which should I use?
- -------------------
- Because Django supports both of the standard Python test frameworks, it's up to
- you and your tastes to decide which one to use. You can even decide to use
- *both*.
- For developers new to testing, however, this choice can seem confusing. Here,
- then, are a few key differences to help you decide which approach is right for
- you:
- * If you've been using Python for a while, ``doctest`` will probably feel
- more "pythonic". It's designed to make writing tests as easy as possible,
- so it requires no overhead of writing classes or methods. You simply put
- tests in docstrings. This has the added advantage of serving as
- documentation (and correct documentation, at that!). However, while
- doctests are good for some simple example code, they are not very good if
- you want to produce either high quality, comprehensive tests or high
- quality documentation. Test failures are often difficult to debug
- as it can be unclear exactly why the test failed. Thus, doctests should
- generally be avoided and used primarily for documentation examples only.
- * The ``unittest`` framework will probably feel very familiar to developers
- coming from Java. ``unittest`` is inspired by Java's JUnit, so you'll
- feel at home with this method if you've used JUnit or any test framework
- inspired by JUnit.
- * If you need to write a bunch of tests that share similar code, then
- you'll appreciate the ``unittest`` framework's organization around
- classes and methods. This makes it easy to abstract common tasks into
- common methods. The framework also supports explicit setup and/or cleanup
- routines, which give you a high level of control over the environment
- in which your test cases are run.
- * If you're writing tests for Django itself, you should use ``unittest``.
- .. _running-tests:
- Running tests
- =============
- Once you've written tests, run them using the :djadmin:`test` command of
- your project's ``manage.py`` utility::
- $ ./manage.py test
- By default, this will run every test in every application in
- :setting:`INSTALLED_APPS`. If you only want to run tests for a particular
- application, add the application name to the command line. For example, if your
- :setting:`INSTALLED_APPS` contains ``'myproject.polls'`` and
- ``'myproject.animals'``, you can run the ``myproject.animals`` unit tests alone
- with this command::
- $ ./manage.py test animals
- Note that we used ``animals``, not ``myproject.animals``.
- You can be even *more* specific by naming an individual test case. To
- run a single test case in an application (for example, the
- ``AnimalTestCase`` described in the "Writing unit tests" section), add
- the name of the test case to the label on the command line::
- $ ./manage.py test animals.AnimalTestCase
- And it gets even more granular than that! To run a *single* test
- method inside a test case, add the name of the test method to the
- label::
- $ ./manage.py test animals.AnimalTestCase.testFluffyAnimals
- .. versionadded:: 1.2
- The ability to select individual doctests was added.
- You can use the same rules if you're using doctests. Django will use the
- test label as a path to the test method or class that you want to run.
- If your ``models.py`` or ``tests.py`` has a function with a doctest, or
- class with a class-level doctest, you can invoke that test by appending the
- name of the test method or class to the label::
- $ ./manage.py test animals.classify
- If you want to run the doctest for a specific method in a class, add the
- name of the method to the label::
- $ ./manage.py test animals.Classifier.run
- If you're using a ``__test__`` dictionary to specify doctests for a
- module, Django will use the label as a key in the ``__test__`` dictionary
- for defined in ``models.py`` and ``tests.py``.
- .. versionadded:: 1.2
- You can now trigger a graceful exit from a test run by pressing ``Ctrl-C``.
- If you press ``Ctrl-C`` while the tests are running, the test runner will
- wait for the currently running test to complete and then exit gracefully.
- During a graceful exit the test runner will output details of any test
- failures, report on how many tests were run and how many errors and failures
- were encountered, and destroy any test databases as usual. Thus pressing
- ``Ctrl-C`` can be very useful if you forget to pass the :djadminopt:`--failfast`
- option, notice that some tests are unexpectedly failing, and want to get details
- on the failures without waiting for the full test run to complete.
- If you do not want to wait for the currently running test to finish, you
- can press ``Ctrl-C`` a second time and the test run will halt immediately,
- but not gracefully. No details of the tests run before the interruption will
- be reported, and any test databases created by the run will not be destroyed.
- .. admonition:: Test with warnings enabled
- It's a good idea to run your tests with Python warnings enabled:
- ``python -Wall manage.py test``. The ``-Wall`` flag tells Python to
- display deprecation warnings. Django, like many other Python libraries,
- uses these warnings to flag when features are going away. It also might
- flag areas in your code that aren't strictly wrong but could benefit
- from a better implementation.
- Running tests outside the test runner
- -------------------------------------
- If you want to run tests outside of ``./manage.py test`` -- for example,
- from a shell prompt -- you will need to set up the test
- environment first. Django provides a convenience method to do this::
- >>> from django.test.utils import setup_test_environment
- >>> setup_test_environment()
- This convenience method sets up the test database, and puts other
- Django features into modes that allow for repeatable testing.
- The call to :meth:`~django.test.utils.setup_test_environment` is made
- automatically as part of the setup of `./manage.py test`. You only
- need to manually invoke this method if you're not using running your
- tests via Django's test runner.
- The test database
- -----------------
- Tests that require a database (namely, model tests) will not use your "real"
- (production) database. Separate, blank databases are created for the tests.
- Regardless of whether the tests pass or fail, the test databases are destroyed
- when all the tests have been executed.
- By default the test databases get their names by prepending ``test_``
- to the value of the :setting:`NAME` settings for the databases
- defined in :setting:`DATABASES`. When using the SQLite database engine
- the tests will by default use an in-memory database (i.e., the
- database will be created in memory, bypassing the filesystem
- entirely!). If you want to use a different database name, specify
- :setting:`TEST_NAME` in the dictionary for any given database in
- :setting:`DATABASES`.
- Aside from using a separate database, the test runner will otherwise
- use all of the same database settings you have in your settings file:
- :setting:`ENGINE`, :setting:`USER`, :setting:`HOST`, etc. The test
- database is created by the user specified by :setting:`USER`, so you'll need
- to make sure that the given user account has sufficient privileges to
- create a new database on the system.
- For fine-grained control over the character encoding of your test
- database, use the :setting:`TEST_CHARSET` option. If you're using
- MySQL, you can also use the :setting:`TEST_COLLATION` option to
- control the particular collation used by the test database. See the
- :doc:`settings documentation </ref/settings>` for details of these
- advanced settings.
- .. _topics-testing-masterslave:
- Testing master/slave configurations
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- .. versionadded:: 1.2
- If you're testing a multiple database configuration with master/slave
- replication, this strategy of creating test databases poses a problem.
- When the test databases are created, there won't be any replication,
- and as a result, data created on the master won't be seen on the
- slave.
- To compensate for this, Django allows you to define that a database is
- a *test mirror*. Consider the following (simplified) example database
- configuration::
- DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.mysql',
- 'NAME': 'myproject',
- 'HOST': 'dbmaster',
- # ... plus some other settings
- },
- 'slave': {
- 'ENGINE': 'django.db.backends.mysql',
- 'NAME': 'myproject',
- 'HOST': 'dbslave',
- 'TEST_MIRROR': 'default'
- # ... plus some other settings
- }
- }
- In this setup, we have two database servers: ``dbmaster``, described
- by the database alias ``default``, and ``dbslave`` described by the
- alias ``slave``. As you might expect, ``dbslave`` has been configured
- by the database administrator as a read slave of ``dbmaster``, so in
- normal activity, any write to ``default`` will appear on ``slave``.
- If Django created two independent test databases, this would break any
- tests that expected replication to occur. However, the ``slave``
- database has been configured as a test mirror (using the
- :setting:`TEST_MIRROR` setting), indicating that under testing,
- ``slave`` should be treated as a mirror of ``default``.
- When the test environment is configured, a test version of ``slave``
- will *not* be created. Instead the connection to ``slave``
- will be redirected to point at ``default``. As a result, writes to
- ``default`` will appear on ``slave`` -- but because they are actually
- the same database, not because there is data replication between the
- two databases.
- .. _topics-testing-creation-dependencies:
- Controlling creation order for test databases
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- .. versionadded:: 1.3
- By default, Django will always create the ``default`` database first.
- However, no guarantees are made on the creation order of any other
- databases in your test setup.
- If your database configuration requires a specific creation order, you
- can specify the dependencies that exist using the
- :setting:`TEST_DEPENDENCIES` setting. Consider the following
- (simplified) example database configuration::
- DATABASES = {
- 'default': {
- # ... db settings
- 'TEST_DEPENDENCIES': ['diamonds']
- },
- 'diamonds': {
- # ... db settings
- },
- 'clubs': {
- # ... db settings
- 'TEST_DEPENDENCIES': ['diamonds']
- },
- 'spades': {
- # ... db settings
- 'TEST_DEPENDENCIES': ['diamonds','hearts']
- },
- 'hearts': {
- # ... db settings
- 'TEST_DEPENDENCIES': ['diamonds','clubs']
- }
- }
- Under this configuration, the ``diamonds`` database will be created first,
- as it is the only database alias without dependencies. The ``default`` and
- ``clubs`` alias will be created next (although the order of creation of this
- pair is not guaranteed); then ``hearts``; and finally ``spades``.
- If there are any circular dependencies in the
- :setting:`TEST_DEPENDENCIES` definition, an ``ImproperlyConfigured``
- exception will be raised.
- Other test conditions
- ---------------------
- Regardless of the value of the :setting:`DEBUG` setting in your configuration
- file, all Django tests run with :setting:`DEBUG`\=False. This is to ensure that
- the observed output of your code matches what will be seen in a production
- setting.
- Understanding the test output
- -----------------------------
- When you run your tests, you'll see a number of messages as the test runner
- prepares itself. You can control the level of detail of these messages with the
- ``verbosity`` option on the command line::
- Creating test database...
- Creating table myapp_animal
- Creating table myapp_mineral
- Loading 'initial_data' fixtures...
- No fixtures found.
- This tells you that the test runner is creating a test database, as described
- in the previous section.
- Once the test database has been created, Django will run your tests.
- If everything goes well, you'll see something like this::
- ----------------------------------------------------------------------
- Ran 22 tests in 0.221s
- OK
- If there are test failures, however, you'll see full details about which tests
- failed::
- ======================================================================
- FAIL: Doctest: ellington.core.throttle.models
- ----------------------------------------------------------------------
- Traceback (most recent call last):
- File "/dev/django/test/doctest.py", line 2153, in runTest
- raise self.failureException(self.format_failure(new.getvalue()))
- AssertionError: Failed doctest test for myapp.models
- File "/dev/myapp/models.py", line 0, in models
- ----------------------------------------------------------------------
- File "/dev/myapp/models.py", line 14, in myapp.models
- Failed example:
- throttle.check("actor A", "action one", limit=2, hours=1)
- Expected:
- True
- Got:
- False
- ----------------------------------------------------------------------
- Ran 2 tests in 0.048s
- FAILED (failures=1)
- A full explanation of this error output is beyond the scope of this document,
- but it's pretty intuitive. You can consult the documentation of Python's
- ``unittest`` library for details.
- Note that the return code for the test-runner script is 1 for any number of
- failed and erroneous tests. If all the tests pass, the return code is 0. This
- feature is useful if you're using the test-runner script in a shell script and
- need to test for success or failure at that level.
- Testing tools
- =============
- Django provides a small set of tools that come in handy when writing tests.
- .. _test-client:
- The test client
- ---------------
- .. module:: django.test.client
- :synopsis: Django's test client.
- The test client is a Python class that acts as a dummy Web browser, allowing
- you to test your views and interact with your Django-powered application
- programmatically.
- Some of the things you can do with the test client are:
- * Simulate GET and POST requests on a URL and observe the response --
- everything from low-level HTTP (result headers and status codes) to
- page content.
- * Test that the correct view is executed for a given URL.
- * Test that a given request is rendered by a given Django template, with
- a template context that contains certain values.
- Note that the test client is not intended to be a replacement for Twill_,
- Selenium_, or other "in-browser" frameworks. Django's test client has
- a different focus. In short:
- * Use Django's test client to establish that the correct view is being
- called and that the view is collecting the correct context data.
- * Use in-browser frameworks such as Twill and Selenium to test *rendered*
- HTML and the *behavior* of Web pages, namely JavaScript functionality.
- A comprehensive test suite should use a combination of both test types.
- .. _Twill: http://twill.idyll.org/
- .. _Selenium: http://seleniumhq.org/
- Overview and a quick example
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- To use the test client, instantiate ``django.test.client.Client`` and retrieve
- Web pages::
- >>> from django.test.client import Client
- >>> c = Client()
- >>> response = c.post('/login/', {'username': 'john', 'password': 'smith'})
- >>> response.status_code
- 200
- >>> response = c.get('/customer/details/')
- >>> response.content
- '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ...'
- As this example suggests, you can instantiate ``Client`` from within a session
- of the Python interactive interpreter.
- Note a few important things about how the test client works:
- * The test client does *not* require the Web server to be running. In fact,
- it will run just fine with no Web server running at all! That's because
- it avoids the overhead of HTTP and deals directly with the Django
- framework. This helps make the unit tests run quickly.
- * When retrieving pages, remember to specify the *path* of the URL, not the
- whole domain. For example, this is correct::
- >>> c.get('/login/')
- This is incorrect::
- >>> c.get('http://www.example.com/login/')
- The test client is not capable of retrieving Web pages that are not
- powered by your Django project. If you need to retrieve other Web pages,
- use a Python standard library module such as urllib_ or urllib2_.
- * To resolve URLs, the test client uses whatever URLconf is pointed-to by
- your :setting:`ROOT_URLCONF` setting.
- * Although the above example would work in the Python interactive
- interpreter, some of the test client's functionality, notably the
- template-related functionality, is only available *while tests are
- running*.
- The reason for this is that Django's test runner performs a bit of black
- magic in order to determine which template was loaded by a given view.
- This black magic (essentially a patching of Django's template system in
- memory) only happens during test running.
- * By default, the test client will disable any CSRF checks
- performed by your site.
- .. versionadded:: 1.2.2
- If, for some reason, you *want* the test client to perform CSRF
- checks, you can create an instance of the test client that
- enforces CSRF checks. To do this, pass in the
- ``enforce_csrf_checks`` argument when you construct your
- client::
- >>> from django.test import Client
- >>> csrf_client = Client(enforce_csrf_checks=True)
- .. _urllib: http://docs.python.org/library/urllib.html
- .. _urllib2: http://docs.python.org/library/urllib2.html
- Making requests
- ~~~~~~~~~~~~~~~
- Use the ``django.test.client.Client`` class to make requests. It requires no
- arguments at time of construction:
- .. class:: Client()
- Once you have a ``Client`` instance, you can call any of the following
- methods:
- .. method:: Client.get(path, data={}, follow=False, **extra)
- Makes a GET request on the provided ``path`` and returns a ``Response``
- object, which is documented below.
- The key-value pairs in the ``data`` dictionary are 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::
- /customers/details/?name=fred&age=7
- The ``extra`` keyword arguments parameter can be used to specify
- headers to be sent in the request. For example::
- >>> c = Client()
- >>> c.get('/customers/details/', {'name': 'fred', 'age': 7},
- ... HTTP_X_REQUESTED_WITH='XMLHttpRequest')
- ...will send the HTTP header ``HTTP_X_REQUESTED_WITH`` to the
- details view, which is a good way to test code paths that use the
- :meth:`django.http.HttpRequest.is_ajax()` method.
- .. admonition:: CGI specification
- The headers sent via ``**extra`` should follow CGI_ specification.
- For example, emulating a different "Host" header as sent in the
- HTTP request from the browser to the server should be passed
- as ``HTTP_HOST``.
- .. _CGI: http://www.w3.org/CGI/
- If you already have the GET arguments in URL-encoded form, you can
- use that encoding instead of using the data argument. For example,
- the previous GET request could also be posed as::
- >>> c = Client()
- >>> c.get('/customers/details/?name=fred&age=7')
- If you provide a URL with both an encoded GET data and a data argument,
- the data argument will take precedence.
- If you set ``follow`` to ``True`` the client will follow any redirects
- and a ``redirect_chain`` attribute will be set in the response object
- containing tuples of the intermediate urls and status codes.
- If you had an url ``/redirect_me/`` that redirected to ``/next/``, that
- redirected to ``/final/``, this is what you'd see::
- >>> response = c.get('/redirect_me/', follow=True)
- >>> response.redirect_chain
- [(u'http://testserver/next/', 302), (u'http://testserver/final/', 302)]
- .. method:: Client.post(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra)
- Makes a POST request on the provided ``path`` and returns a
- ``Response`` object, which is documented below.
- The key-value pairs in the ``data`` dictionary are used to submit POST
- data. For example::
- >>> c = Client()
- >>> c.post('/login/', {'name': 'fred', 'passwd': 'secret'})
- ...will result in the evaluation of a POST request to this URL::
- /login/
- ...with this POST data::
- name=fred&passwd=secret
- If you provide ``content_type`` (e.g., ``text/xml`` for an XML
- payload), the contents of ``data`` will be sent as-is in the POST
- request, using ``content_type`` in the HTTP ``Content-Type`` header.
- 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``. In this case, the key-value pairs in ``data``
- 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
- the selections for a ``<select multiple>`` -- provide the values as a
- list or tuple for the required key. For example, this value of ``data``
- would submit three selected values for the field named ``choices``::
- {'choices': ('a', 'b', 'd')}
- 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. For example::
- >>> c = Client()
- >>> f = open('wishlist.doc')
- >>> c.post('/customers/wishes/', {'name': 'fred', 'attachment': f})
- >>> f.close()
- (The name ``attachment`` here is not relevant; use whatever name your
- file-processing code expects.)
- Note that if you wish to use the same file handle for multiple
- ``post()`` calls then you will need to manually reset the file
- pointer between posts. The easiest way to do this is to
- manually close the file after it has been provided to
- ``post()``, as demonstrated above.
- You should also ensure that the file is opened in a way that
- allows the data to be read. If your file contains binary data
- such as an image, this means you will need to open the file in
- ``rb`` (read binary) mode.
- The ``extra`` argument acts the same as for :meth:`Client.get`.
- If the URL you request with a POST contains encoded parameters, these
- parameters will be made available in the request.GET data. For example,
- if you were to make the request::
- >>> c.post('/login/?visitor=true', {'name': 'fred', 'passwd': 'secret'})
- ... the view handling this request could interrogate request.POST
- to retrieve the username and password, and could interrogate request.GET
- to determine if the user was a visitor.
- If you set ``follow`` to ``True`` the client will follow any redirects
- and a ``redirect_chain`` attribute will be set in the response object
- containing tuples of the intermediate urls and status codes.
- .. method:: Client.head(path, data={}, follow=False, **extra)
- Makes a HEAD request on the provided ``path`` and returns a ``Response``
- object. Useful for testing RESTful interfaces. Acts just like
- :meth:`Client.get` except it does not return a message body.
- If you set ``follow`` to ``True`` the client will follow any redirects
- and a ``redirect_chain`` attribute will be set in the response object
- containing tuples of the intermediate urls and status codes.
- .. method:: Client.options(path, data={}, follow=False, **extra)
- Makes an OPTIONS request on the provided ``path`` and returns a
- ``Response`` object. Useful for testing RESTful interfaces.
- If you set ``follow`` to ``True`` the client will follow any redirects
- and a ``redirect_chain`` attribute will be set in the response object
- containing tuples of the intermediate urls and status codes.
- The ``extra`` argument acts the same as for :meth:`Client.get`.
- .. method:: Client.put(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra)
- Makes a PUT request on the provided ``path`` and returns a
- ``Response`` object. Useful for testing RESTful interfaces. Acts just
- like :meth:`Client.post` except with the PUT request method.
- If you set ``follow`` to ``True`` the client will follow any redirects
- and a ``redirect_chain`` attribute will be set in the response object
- containing tuples of the intermediate urls and status codes.
- .. method:: Client.delete(path, follow=False, **extra)
- Makes an DELETE request on the provided ``path`` and returns a
- ``Response`` object. Useful for testing RESTful interfaces.
- If you set ``follow`` to ``True`` the client will follow any redirects
- and a ``redirect_chain`` attribute will be set in the response object
- containing tuples of the intermediate urls and status codes.
- The ``extra`` argument acts the same as for :meth:`Client.get`.
- .. method:: Client.login(**credentials)
- If your site uses Django's :doc:`authentication system</topics/auth>`
- and you deal with logging in users, you can use the test client's
- ``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 session data required to pass any login-based tests that may form
- part of a view.
- The format of the ``credentials`` argument depends on which
- :ref:`authentication backend <authentication-backends>` you're using
- (which is configured by your :setting:`AUTHENTICATION_BACKENDS`
- setting). If you're using the standard authentication backend provided
- by Django (``ModelBackend``), ``credentials`` should be the user's
- username and password, provided as keyword arguments::
- >>> c = Client()
- >>> c.login(username='fred', password='secret')
- # 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 different credentials. It requires whichever credentials are
- required by your backend's ``authenticate()`` method.
- ``login()`` returns ``True`` if it the credentials were accepted and
- login was successful.
- Finally, you'll need to remember to create user accounts before you can
- use this method. As we explained above, the test runner is executed
- using a test database, which contains no users by default. As a result,
- user accounts that are valid on your production site will not work
- under test conditions. You'll need to create users as part of the test
- suite -- either manually (using the Django model API) or with a test
- fixture. Remember that if you want your test user to have a password,
- you can't set the user's password by setting the password attribute
- directly -- you must use the
- :meth:`~django.contrib.auth.models.User.set_password()` function to
- store a correctly hashed password. Alternatively, you can use the
- :meth:`~django.contrib.auth.models.UserManager.create_user` helper
- method to create a new user with a correctly hashed password.
- .. method:: Client.logout()
- If your site uses Django's :doc:`authentication system</topics/auth>`,
- the ``logout()`` method can be used to simulate the effect of a user
- logging out of your site.
- After you call this method, the test client will have all the cookies
- and session data cleared to defaults. Subsequent requests will appear
- to come from an AnonymousUser.
- Testing responses
- ~~~~~~~~~~~~~~~~~
- The ``get()`` and ``post()`` methods both return a ``Response`` object. This
- ``Response`` object is *not* the same as the ``HttpResponse`` object returned
- Django views; the test response object has some additional data useful for
- test code to verify.
- Specifically, a ``Response`` object has the following attributes:
- .. class:: Response()
- .. attribute:: client
- The test client that was used to make the request that resulted in the
- response.
- .. attribute:: content
- The body of the response, as a string. This is the final page content as
- rendered by the view, or any error message.
- .. attribute:: context
- The template ``Context`` instance that was used to render the template that
- produced the response content.
- If the rendered page used multiple templates, then ``context`` will be a
- list of ``Context`` objects, in the order in which they were rendered.
- Regardless of the number of templates used during rendering, you can
- retrieve context values using the ``[]`` operator. For example, the
- context variable ``name`` could be retrieved using::
- >>> response = client.get('/foo/')
- >>> response.context['name']
- 'Arthur'
- .. attribute:: request
- The request data that stimulated the response.
- .. attribute:: status_code
- The HTTP status of the response, as an integer. See RFC2616_ for a full
- list of HTTP status codes.
- .. versionadded:: 1.3
- .. attribute:: templates
- A list of ``Template`` instances used to render the final content, in
- the order they were rendered. For each template in the list, use
- ``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'``.)
- 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
- content type of a response using ``response['Content-Type']``.
- .. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
- Exceptions
- ~~~~~~~~~~
- If you point the test client at a view that raises an exception, that exception
- will be visible in the test case. You can then use a standard ``try...except``
- block or ``unittest.TestCase.assertRaises()`` to test for exceptions.
- The only exceptions that are not visible to the test client are ``Http404``,
- ``PermissionDenied`` and ``SystemExit``. Django catches these exceptions
- internally and converts them into the appropriate HTTP response codes. In these
- cases, you can check ``response.status_code`` in your test.
- Persistent state
- ~~~~~~~~~~~~~~~~
- The test client is stateful. If a response returns a cookie, then that cookie
- will be stored in the test client and sent with all subsequent ``get()`` and
- ``post()`` requests.
- Expiration policies for these cookies are not followed. If you want a cookie
- to expire, either delete it manually or create a new ``Client`` instance (which
- will effectively delete all cookies).
- A test client has two attributes that store persistent state information. You
- can access these properties as part of a test condition.
- .. attribute:: Client.cookies
- A Python ``SimpleCookie`` object, containing the current values of all the
- client cookies. See the `Cookie module documentation`_ for more.
- .. attribute:: Client.session
- A dictionary-like object containing session information. See the
- :doc:`session documentation</topics/http/sessions>` for full details.
- To modify the session and then save it, it must be stored in a variable
- first (because a new ``SessionStore`` is created every time this property
- is accessed)::
- def test_something(self):
- session = self.client.session
- session['somekey'] = 'test'
- session.save()
- .. _Cookie module documentation: http://docs.python.org/library/cookie.html
- Example
- ~~~~~~~
- The following is a simple unit test using the test client::
- from django.utils 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):
- # Issue a GET request.
- response = self.client.get('/customer/details/')
- # Check that the response is 200 OK.
- self.assertEqual(response.status_code, 200)
- # Check that the rendered context contains 5 customers.
- self.assertEqual(len(response.context['customers']), 5)
- The request factory
- -------------------
- .. Class:: RequestFactory
- .. versionadded:: 1.3
- The :class:`~django.test.client.RequestFactory` shares the same API as
- the test client. However, instead of behaving like a browser, the
- RequestFactory provides a way to generate a request instance that can
- be used as the first argument to any view. This means you can test a
- view function the same way as you would test any other function -- as
- a black box, with exactly known inputs, testing for specific outputs.
- The API for the :class:`~django.test.client.RequestFactory` is a slightly
- restricted subset of the test client API:
- * It only has access to the HTTP methods :meth:`~Client.get()`,
- :meth:`~Client.post()`, :meth:`~Client.put()`,
- :meth:`~Client.delete()`, :meth:`~Client.head()` and
- :meth:`~Client.options()`.
- * These methods accept all the same arguments *except* for
- ``follows``. Since this is just a factory for producing
- requests, it's up to you to handle the response.
- * It does not support middleware. Session and authentication
- attributes must be supplied by the test itself if required
- for the view to function properly.
- Example
- ~~~~~~~
- The following is a simple unit test using the request factory::
- from django.utils import unittest
- from django.test.client import RequestFactory
- class SimpleTest(unittest.TestCase):
- def setUp(self):
- # Every test needs access to the request factory.
- self.factory = RequestFactory()
- def test_details(self):
- # Create an instance of a GET request.
- request = self.factory.get('/customer/details')
- # Test my_view() as if it were deployed at /customer/details
- response = my_view(request)
- self.assertEqual(response.status_code, 200)
- TestCase
- --------
- .. currentmodule:: django.test
- Normal Python unit test classes extend a base class of ``unittest.TestCase``.
- Django provides an extension of this base class:
- .. class:: TestCase()
- This class provides some additional capabilities that can be useful for testing
- Web sites.
- Converting 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 functionality
- will continue to be available, but it will be augmented with some useful
- additions, including:
- * Automatic loading of fixtures.
- * Wraps each test in a transaction.
- * Creates a TestClient instance.
- * Django-specific assertions for testing for things
- like redirection and form errors.
- .. class:: TransactionTestCase()
- Django ``TestCase`` classes make use of database transaction facilities, if
- available, to speed up the process of resetting the database to a known state
- at the beginning of each test. A consequence of this, however, is that the
- effects of transaction commit and rollback cannot be tested by a Django
- ``TestCase`` class. If your test requires testing of such transactional
- behavior, you should use a Django ``TransactionTestCase``.
- ``TransactionTestCase`` and ``TestCase`` are identical except for the manner
- in which the database is reset to a known state and the ability for test code
- to test the effects of commit and rollback. A ``TransactionTestCase`` resets
- the database before the test runs by truncating all tables and reloading
- initial data. A ``TransactionTestCase`` may call commit and rollback and
- observe the effects of these calls on the database.
- A ``TestCase``, on the other hand, does not truncate tables and reload initial
- data at the beginning of a test. Instead, it encloses the test code in a
- database transaction that is rolled back at the end of the test. It also
- prevents the code under test from issuing any commit or rollback operations
- on the database, to ensure that the rollback at the end of the test restores
- the database to its initial state. In order to guarantee that all ``TestCase``
- code starts with a clean database, the Django test runner runs all ``TestCase``
- tests first, before any other tests (e.g. doctests) that may alter the
- database without restoring it to its original state.
- When running on a database that does not support rollback (e.g. MySQL with the
- MyISAM storage engine), ``TestCase`` falls back to initializing the database
- by truncating tables and reloading initial data.
- .. note::
- The ``TestCase`` use of rollback to un-do the effects of the test code
- may reveal previously-undetected errors in test code. For example,
- test code that assumes primary keys values will be assigned starting at
- one may find that assumption no longer holds true when rollbacks instead
- of table truncation are being used to reset the database. Similarly,
- the reordering of tests so that all ``TestCase`` classes run first may
- reveal unexpected dependencies on test case ordering. In such cases a
- quick fix is to switch the ``TestCase`` to a ``TransactionTestCase``.
- A better long-term fix, that allows the test to take advantage of the
- speed benefit of ``TestCase``, is to fix the underlying test problem.
- Default test client
- ~~~~~~~~~~~~~~~~~~~
- .. attribute:: TestCase.client
- 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, so you don't have to
- worry about state (such as cookies) carrying over from one test to another.
- This means, instead of instantiating a ``Client`` in each test::
- from django.utils import unittest
- from django.test.client import Client
- class SimpleTest(unittest.TestCase):
- def test_details(self):
- client = Client()
- response = client.get('/customer/details/')
- self.assertEqual(response.status_code, 200)
- def test_index(self):
- client = Client()
- response = client.get('/customer/index/')
- self.assertEqual(response.status_code, 200)
- ...you can just refer to ``self.client``, like so::
- from django.test import TestCase
- class SimpleTest(TestCase):
- def test_details(self):
- response = self.client.get('/customer/details/')
- self.assertEqual(response.status_code, 200)
- def test_index(self):
- response = self.client.get('/customer/index/')
- self.assertEqual(response.status_code, 200)
- Customizing the test client
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- .. versionadded:: 1.3
- .. attribute:: TestCase.client_class
- If you want to use a different ``Client`` class (for example, a subclass
- with customized behavior), use the :attr:`~TestCase.client_class` class
- attribute::
- from django.test import TestCase
- from django.test.client import Client
- class MyTestClient(Client):
- # Specialized methods for your environment...
- class MyTest(TestCase):
- client_class = MyTestClient
- def test_my_stuff(self):
- # Here self.client is an instance of MyTestClient...
- .. _topics-testing-fixtures:
- Fixture loading
- ~~~~~~~~~~~~~~~
- .. attribute:: TestCase.fixtures
- A test case for a database-backed Web site 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's custom ``TestCase`` class provides a way of loading **fixtures**.
- 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
- 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
- :djadmin:`manage.py dumpdata <dumpdata>` com…
Large files files are truncated, but you can click here to view the full file