mirror of https://github.com/django/django.git
[1.5.x] Fixed #19497 -- Refactored testing docs.
Thanks Tim Graham for the review and suggestions.
d19109fd37
from master.
This commit is contained in:
parent
3aba929bcc
commit
903892be7b
|
@ -180,7 +180,11 @@ testing of Django applications:
|
||||||
:doc:`Overview <ref/django-admin>` |
|
:doc:`Overview <ref/django-admin>` |
|
||||||
:doc:`Adding custom commands <howto/custom-management-commands>`
|
:doc:`Adding custom commands <howto/custom-management-commands>`
|
||||||
|
|
||||||
* **Testing:** :doc:`Overview <topics/testing>`
|
* **Testing:**
|
||||||
|
:doc:`Introduction <topics/testing/index>` |
|
||||||
|
:doc:`Writing and running tests <topics/testing/overview>` |
|
||||||
|
:doc:`Advanced topics <topics/testing/advanced>` |
|
||||||
|
:doc:`Doctests <topics/testing/doctests>`
|
||||||
|
|
||||||
* **Deployment:**
|
* **Deployment:**
|
||||||
:doc:`Overview <howto/deployment/index>` |
|
:doc:`Overview <howto/deployment/index>` |
|
||||||
|
|
|
@ -15,8 +15,8 @@ The tests cover:
|
||||||
We appreciate any and all contributions to the test suite!
|
We appreciate any and all contributions to the test suite!
|
||||||
|
|
||||||
The Django tests all use the testing infrastructure that ships with Django for
|
The Django tests all use the testing infrastructure that ships with Django for
|
||||||
testing applications. See :doc:`Testing Django applications </topics/testing>`
|
testing applications. See :doc:`Testing Django applications
|
||||||
for an explanation of how to write new tests.
|
</topics/testing/overview>` for an explanation of how to write new tests.
|
||||||
|
|
||||||
.. _running-unit-tests:
|
.. _running-unit-tests:
|
||||||
|
|
||||||
|
|
|
@ -281,7 +281,7 @@ correctly in a couple different situations.
|
||||||
computer programming, so there's lots of information out there:
|
computer programming, so there's lots of information out there:
|
||||||
|
|
||||||
* A good first look at writing tests for Django can be found in the
|
* A good first look at writing tests for Django can be found in the
|
||||||
documentation on :doc:`Testing Django applications</topics/testing/>`.
|
documentation on :doc:`Testing Django applications </topics/testing/overview>`.
|
||||||
* Dive Into Python (a free online book for beginning Python developers)
|
* Dive Into Python (a free online book for beginning Python developers)
|
||||||
includes a great `introduction to Unit Testing`__.
|
includes a great `introduction to Unit Testing`__.
|
||||||
* After reading those, if you want something a little meatier to sink
|
* After reading those, if you want something a little meatier to sink
|
||||||
|
|
|
@ -632,7 +632,7 @@ a piece of code, it usually means that code should be refactored or removed.
|
||||||
Coverage will help to identify dead code. See
|
Coverage will help to identify dead code. See
|
||||||
:ref:`topics-testing-code-coverage` for details.
|
:ref:`topics-testing-code-coverage` for details.
|
||||||
|
|
||||||
:doc:`Testing Django applications </topics/testing>` has comprehensive
|
:doc:`Testing Django applications </topics/testing/index>` has comprehensive
|
||||||
information about testing.
|
information about testing.
|
||||||
|
|
||||||
.. _Selenium: http://seleniumhq.org/
|
.. _Selenium: http://seleniumhq.org/
|
||||||
|
|
|
@ -71,7 +71,7 @@ of 1.0. This includes these APIs:
|
||||||
external template tags. Before adding any such tags, we'll ensure that
|
external template tags. Before adding any such tags, we'll ensure that
|
||||||
Django raises an error if it tries to load tags with duplicate names.
|
Django raises an error if it tries to load tags with duplicate names.
|
||||||
|
|
||||||
- :doc:`Testing </topics/testing>`
|
- :doc:`Testing </topics/testing/index>`
|
||||||
|
|
||||||
- :doc:`django-admin utility </ref/django-admin>`.
|
- :doc:`django-admin utility </ref/django-admin>`.
|
||||||
|
|
||||||
|
|
|
@ -1036,7 +1036,7 @@ test <app or test identifier>
|
||||||
|
|
||||||
.. django-admin:: test
|
.. django-admin:: test
|
||||||
|
|
||||||
Runs tests for all installed models. See :doc:`/topics/testing` for more
|
Runs tests for all installed models. See :doc:`/topics/testing/index` for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
.. django-admin-option:: --failfast
|
.. django-admin-option:: --failfast
|
||||||
|
@ -1072,7 +1072,7 @@ For example, this command::
|
||||||
|
|
||||||
...would perform the following steps:
|
...would perform the following steps:
|
||||||
|
|
||||||
1. Create a test database, as described in :doc:`/topics/testing`.
|
1. Create a test database, as described in :ref:`the-test-database`.
|
||||||
2. Populate the test database with fixture data from the given fixtures.
|
2. Populate the test database with fixture data from the given fixtures.
|
||||||
(For more on fixtures, see the documentation for ``loaddata`` above.)
|
(For more on fixtures, see the documentation for ``loaddata`` above.)
|
||||||
3. Runs the Django development server (as in ``runserver``), pointed at
|
3. Runs the Django development server (as in ``runserver``), pointed at
|
||||||
|
@ -1080,7 +1080,7 @@ For example, this command::
|
||||||
|
|
||||||
This is useful in a number of ways:
|
This is useful in a number of ways:
|
||||||
|
|
||||||
* When you're writing :doc:`unit tests </topics/testing>` of how your views
|
* When you're writing :doc:`unit tests </topics/testing/overview>` of how your views
|
||||||
act with certain fixture data, you can use ``testserver`` to interact with
|
act with certain fixture data, you can use ``testserver`` to interact with
|
||||||
the views in a Web browser, manually.
|
the views in a Web browser, manually.
|
||||||
|
|
||||||
|
|
|
@ -562,7 +562,7 @@ If the default value (``None``) is used with the SQLite database engine, the
|
||||||
tests will use a memory resident database. For all other database engines the
|
tests will use a memory resident database. For all other database engines the
|
||||||
test database will use the name ``'test_' + DATABASE_NAME``.
|
test database will use the name ``'test_' + DATABASE_NAME``.
|
||||||
|
|
||||||
See :doc:`/topics/testing`.
|
See :ref:`the-test-database`.
|
||||||
|
|
||||||
.. setting:: TEST_CREATE
|
.. setting:: TEST_CREATE
|
||||||
|
|
||||||
|
@ -1982,9 +1982,7 @@ TEST_RUNNER
|
||||||
Default: ``'django.test.simple.DjangoTestSuiteRunner'``
|
Default: ``'django.test.simple.DjangoTestSuiteRunner'``
|
||||||
|
|
||||||
The name of the class to use for starting the test suite. See
|
The name of the class to use for starting the test suite. See
|
||||||
:doc:`/topics/testing`.
|
:ref:`other-testing-frameworks`.
|
||||||
|
|
||||||
.. _Testing Django Applications: ../testing/
|
|
||||||
|
|
||||||
.. setting:: THOUSAND_SEPARATOR
|
.. setting:: THOUSAND_SEPARATOR
|
||||||
|
|
||||||
|
|
|
@ -476,7 +476,7 @@ Test signals
|
||||||
.. module:: django.test.signals
|
.. module:: django.test.signals
|
||||||
:synopsis: Signals sent during testing.
|
:synopsis: Signals sent during testing.
|
||||||
|
|
||||||
Signals only sent when :doc:`running tests </topics/testing>`.
|
Signals only sent when :ref:`running tests <running-tests>`.
|
||||||
|
|
||||||
setting_changed
|
setting_changed
|
||||||
---------------
|
---------------
|
||||||
|
|
|
@ -220,7 +220,7 @@ supported :doc:`serialization formats </topics/serialization>`, that will be
|
||||||
loaded into your database at the start of your tests. This makes testing with
|
loaded into your database at the start of your tests. This makes testing with
|
||||||
real data much easier.
|
real data much easier.
|
||||||
|
|
||||||
See :doc:`the testing documentation </topics/testing>` for the full details.
|
See :doc:`the testing documentation </topics/testing/index>` for the full details.
|
||||||
|
|
||||||
Improvements to the admin interface
|
Improvements to the admin interface
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
|
@ -51,7 +51,7 @@ Performance improvements
|
||||||
|
|
||||||
.. currentmodule:: django.test
|
.. currentmodule:: django.test
|
||||||
|
|
||||||
Tests written using Django's :doc:`testing framework </topics/testing>` now run
|
Tests written using Django's :doc:`testing framework </topics/testing/index>` now run
|
||||||
dramatically faster (as much as 10 times faster in many cases).
|
dramatically faster (as much as 10 times faster in many cases).
|
||||||
|
|
||||||
This was accomplished through the introduction of transaction-based tests: when
|
This was accomplished through the introduction of transaction-based tests: when
|
||||||
|
|
|
@ -102,7 +102,7 @@ Testing improvements
|
||||||
.. currentmodule:: django.test.client
|
.. currentmodule:: django.test.client
|
||||||
|
|
||||||
A couple of small but very useful improvements have been made to the
|
A couple of small but very useful improvements have been made to the
|
||||||
:doc:`testing framework </topics/testing>`:
|
:doc:`testing framework </topics/testing/index>`:
|
||||||
|
|
||||||
* The test :class:`Client` now can automatically follow redirects with the
|
* The test :class:`Client` now can automatically follow redirects with the
|
||||||
``follow`` argument to :meth:`Client.get` and :meth:`Client.post`. This
|
``follow`` argument to :meth:`Client.get` and :meth:`Client.post`. This
|
||||||
|
|
|
@ -264,14 +264,14 @@ Testing improvements
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
A few notable improvements have been made to the :doc:`testing framework
|
A few notable improvements have been made to the :doc:`testing framework
|
||||||
</topics/testing>`.
|
</topics/testing/index>`.
|
||||||
|
|
||||||
Test performance improvements
|
Test performance improvements
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. currentmodule:: django.test
|
.. currentmodule:: django.test
|
||||||
|
|
||||||
Tests written using Django's :doc:`testing framework </topics/testing>` now run
|
Tests written using Django's :doc:`testing framework </topics/testing/index>` now run
|
||||||
dramatically faster (as much as 10 times faster in many cases).
|
dramatically faster (as much as 10 times faster in many cases).
|
||||||
|
|
||||||
This was accomplished through the introduction of transaction-based tests: when
|
This was accomplished through the introduction of transaction-based tests: when
|
||||||
|
|
|
@ -13,7 +13,7 @@ Introductions to all the key parts of Django you'll need to know:
|
||||||
templates
|
templates
|
||||||
class-based-views/index
|
class-based-views/index
|
||||||
files
|
files
|
||||||
testing
|
testing/index
|
||||||
auth
|
auth
|
||||||
cache
|
cache
|
||||||
conditional-view-processing
|
conditional-view-processing
|
||||||
|
|
|
@ -135,7 +135,7 @@ table once ``syncdb`` has created it. After creating a database user with these
|
||||||
permissions, you'll specify the details in your project's settings file,
|
permissions, you'll specify the details in your project's settings file,
|
||||||
see :setting:`DATABASES` for details.
|
see :setting:`DATABASES` for details.
|
||||||
|
|
||||||
If you're using Django's :doc:`testing framework</topics/testing>` to test
|
If you're using Django's :doc:`testing framework</topics/testing/index>` to test
|
||||||
database queries, Django will need permission to create a test database.
|
database queries, Django will need permission to create a test database.
|
||||||
|
|
||||||
.. _PostgreSQL: http://www.postgresql.org/
|
.. _PostgreSQL: http://www.postgresql.org/
|
||||||
|
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,429 @@
|
||||||
|
=======================
|
||||||
|
Advanced testing topics
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The request factory
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. module:: django.test.client
|
||||||
|
|
||||||
|
.. class:: RequestFactory
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
.. _topics-testing-advanced-multidb:
|
||||||
|
|
||||||
|
Tests and multiple databases
|
||||||
|
============================
|
||||||
|
|
||||||
|
.. _topics-testing-masterslave:
|
||||||
|
|
||||||
|
Testing master/slave configurations
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
.. _other-testing-frameworks:
|
||||||
|
|
||||||
|
Using different testing frameworks
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Clearly, :mod:`doctest` and :mod:`unittest` are not the only Python testing
|
||||||
|
frameworks. While Django doesn't provide explicit support for alternative
|
||||||
|
frameworks, it does provide a way to invoke tests constructed for an
|
||||||
|
alternative framework as if they were normal Django tests.
|
||||||
|
|
||||||
|
When you run ``./manage.py test``, Django looks at the :setting:`TEST_RUNNER`
|
||||||
|
setting to determine what to do. By default, :setting:`TEST_RUNNER` points to
|
||||||
|
``'django.test.simple.DjangoTestSuiteRunner'``. This class defines the default Django
|
||||||
|
testing behavior. This behavior involves:
|
||||||
|
|
||||||
|
#. Performing global pre-test setup.
|
||||||
|
|
||||||
|
#. Looking for unit tests and doctests in the ``models.py`` and
|
||||||
|
``tests.py`` files in each installed application.
|
||||||
|
|
||||||
|
#. Creating the test databases.
|
||||||
|
|
||||||
|
#. Running ``syncdb`` to install models and initial data into the test
|
||||||
|
databases.
|
||||||
|
|
||||||
|
#. Running the unit tests and doctests that are found.
|
||||||
|
|
||||||
|
#. Destroying the test databases.
|
||||||
|
|
||||||
|
#. Performing global post-test teardown.
|
||||||
|
|
||||||
|
If you define your own test runner class and point :setting:`TEST_RUNNER` at
|
||||||
|
that class, Django will execute your test runner whenever you run
|
||||||
|
``./manage.py test``. In this way, it is possible to use any test framework
|
||||||
|
that can be executed from Python code, or to modify the Django test execution
|
||||||
|
process to satisfy whatever testing requirements you may have.
|
||||||
|
|
||||||
|
.. _topics-testing-test_runner:
|
||||||
|
|
||||||
|
Defining a test runner
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. currentmodule:: django.test.simple
|
||||||
|
|
||||||
|
A test runner is a class defining a ``run_tests()`` method. Django ships
|
||||||
|
with a ``DjangoTestSuiteRunner`` class that defines the default Django
|
||||||
|
testing behavior. This class defines the ``run_tests()`` entry point,
|
||||||
|
plus a selection of other methods that are used to by ``run_tests()`` to
|
||||||
|
set up, execute and tear down the test suite.
|
||||||
|
|
||||||
|
.. class:: DjangoTestSuiteRunner(verbosity=1, interactive=True, failfast=True, **kwargs)
|
||||||
|
|
||||||
|
``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.
|
||||||
|
|
||||||
|
If ``interactive`` is ``True``, the test suite has permission to ask the
|
||||||
|
user for instructions when the test suite is executed. An example of this
|
||||||
|
behavior would be asking for permission to delete an existing test
|
||||||
|
database. If ``interactive`` is ``False``, the test suite must be able to
|
||||||
|
run without any manual intervention.
|
||||||
|
|
||||||
|
If ``failfast`` is ``True``, the test suite will stop running after the
|
||||||
|
first test failure is detected.
|
||||||
|
|
||||||
|
Django will, from time to time, extend the capabilities of
|
||||||
|
the test runner by adding new arguments. The ``**kwargs`` declaration
|
||||||
|
allows for this expansion. If you subclass ``DjangoTestSuiteRunner`` or
|
||||||
|
write your own test runner, ensure accept and handle the ``**kwargs``
|
||||||
|
parameter.
|
||||||
|
|
||||||
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
|
Your test runner may also define additional command-line options.
|
||||||
|
If you add an ``option_list`` attribute to a subclassed test runner,
|
||||||
|
those options will be added to the list of command-line options that
|
||||||
|
the :djadmin:`test` command can use.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
.. attribute:: DjangoTestSuiteRunner.option_list
|
||||||
|
|
||||||
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
|
This is the tuple of ``optparse`` options which will be fed into the
|
||||||
|
management command's ``OptionParser`` for parsing arguments. See the
|
||||||
|
documentation for Python's ``optparse`` module for more details.
|
||||||
|
|
||||||
|
Methods
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
.. method:: DjangoTestSuiteRunner.run_tests(test_labels, extra_tests=None, **kwargs)
|
||||||
|
|
||||||
|
Run the test suite.
|
||||||
|
|
||||||
|
``test_labels`` is a list of strings describing the tests to be run. A test
|
||||||
|
label can take one of three forms:
|
||||||
|
|
||||||
|
* ``app.TestCase.test_method`` -- Run a single test method in a test
|
||||||
|
case.
|
||||||
|
* ``app.TestCase`` -- Run all the test methods in a test case.
|
||||||
|
* ``app`` -- Search for and run all tests in the named application.
|
||||||
|
|
||||||
|
If ``test_labels`` has a value of ``None``, the test runner should run
|
||||||
|
search for tests in all the applications in :setting:`INSTALLED_APPS`.
|
||||||
|
|
||||||
|
``extra_tests`` is a list of extra ``TestCase`` instances to add to the
|
||||||
|
suite that is executed by the test runner. These extra tests are run
|
||||||
|
in addition to those discovered in the modules listed in ``test_labels``.
|
||||||
|
|
||||||
|
This method should return the number of tests that failed.
|
||||||
|
|
||||||
|
.. method:: DjangoTestSuiteRunner.setup_test_environment(**kwargs)
|
||||||
|
|
||||||
|
Sets up the test environment ready for testing.
|
||||||
|
|
||||||
|
.. method:: DjangoTestSuiteRunner.build_suite(test_labels, extra_tests=None, **kwargs)
|
||||||
|
|
||||||
|
Constructs a test suite that matches the test labels provided.
|
||||||
|
|
||||||
|
``test_labels`` is a list of strings describing the tests to be run. A test
|
||||||
|
label can take one of three forms:
|
||||||
|
|
||||||
|
* ``app.TestCase.test_method`` -- Run a single test method in a test
|
||||||
|
case.
|
||||||
|
* ``app.TestCase`` -- Run all the test methods in a test case.
|
||||||
|
* ``app`` -- Search for and run all tests in the named application.
|
||||||
|
|
||||||
|
If ``test_labels`` has a value of ``None``, the test runner should run
|
||||||
|
search for tests in all the applications in :setting:`INSTALLED_APPS`.
|
||||||
|
|
||||||
|
``extra_tests`` is a list of extra ``TestCase`` instances to add to the
|
||||||
|
suite that is executed by the test runner. These extra tests are run
|
||||||
|
in addition to those discovered in the modules listed in ``test_labels``.
|
||||||
|
|
||||||
|
Returns a ``TestSuite`` instance ready to be run.
|
||||||
|
|
||||||
|
.. method:: DjangoTestSuiteRunner.setup_databases(**kwargs)
|
||||||
|
|
||||||
|
Creates the test databases.
|
||||||
|
|
||||||
|
Returns a data structure that provides enough detail to undo the changes
|
||||||
|
that have been made. This data will be provided to the ``teardown_databases()``
|
||||||
|
function at the conclusion of testing.
|
||||||
|
|
||||||
|
.. method:: DjangoTestSuiteRunner.run_suite(suite, **kwargs)
|
||||||
|
|
||||||
|
Runs the test suite.
|
||||||
|
|
||||||
|
Returns the result produced by the running the test suite.
|
||||||
|
|
||||||
|
.. method:: DjangoTestSuiteRunner.teardown_databases(old_config, **kwargs)
|
||||||
|
|
||||||
|
Destroys the test databases, restoring pre-test conditions.
|
||||||
|
|
||||||
|
``old_config`` is a data structure defining the changes in the
|
||||||
|
database configuration that need to be reversed. It is the return
|
||||||
|
value of the ``setup_databases()`` method.
|
||||||
|
|
||||||
|
.. method:: DjangoTestSuiteRunner.teardown_test_environment(**kwargs)
|
||||||
|
|
||||||
|
Restores the pre-test environment.
|
||||||
|
|
||||||
|
.. method:: DjangoTestSuiteRunner.suite_result(suite, result, **kwargs)
|
||||||
|
|
||||||
|
Computes and returns a return code based on a test suite, and the result
|
||||||
|
from that test suite.
|
||||||
|
|
||||||
|
|
||||||
|
Testing utilities
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. module:: django.test.utils
|
||||||
|
:synopsis: Helpers to write custom test runners.
|
||||||
|
|
||||||
|
To assist in the creation of your own test runner, Django provides a number of
|
||||||
|
utility methods in the ``django.test.utils`` module.
|
||||||
|
|
||||||
|
.. function:: setup_test_environment()
|
||||||
|
|
||||||
|
Performs any global pre-test setup, such as the installing the
|
||||||
|
instrumentation of the template rendering system and setting up
|
||||||
|
the dummy email outbox.
|
||||||
|
|
||||||
|
.. function:: teardown_test_environment()
|
||||||
|
|
||||||
|
Performs any global post-test teardown, such as removing the black
|
||||||
|
magic hooks into the template system and restoring normal email
|
||||||
|
services.
|
||||||
|
|
||||||
|
.. currentmodule:: django.db.connection.creation
|
||||||
|
|
||||||
|
The creation module of the database backend (``connection.creation``)
|
||||||
|
also provides some utilities that can be useful during testing.
|
||||||
|
|
||||||
|
.. function:: create_test_db([verbosity=1, autoclobber=False])
|
||||||
|
|
||||||
|
Creates a new test database and runs ``syncdb`` against it.
|
||||||
|
|
||||||
|
``verbosity`` has the same behavior as in ``run_tests()``.
|
||||||
|
|
||||||
|
``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.
|
||||||
|
|
||||||
|
Returns the name of the test database that it created.
|
||||||
|
|
||||||
|
``create_test_db()`` has the side effect of modifying the value of
|
||||||
|
:setting:`NAME` in :setting:`DATABASES` to match the name of the test
|
||||||
|
database.
|
||||||
|
|
||||||
|
.. function:: destroy_test_db(old_database_name, [verbosity=1])
|
||||||
|
|
||||||
|
Destroys the database whose name is the value of :setting:`NAME` in
|
||||||
|
:setting:`DATABASES`, and sets :setting:`NAME` to the value of
|
||||||
|
``old_database_name``.
|
||||||
|
|
||||||
|
The ``verbosity`` argument has the same behavior as for
|
||||||
|
:class:`~django.test.simple.DjangoTestSuiteRunner`.
|
||||||
|
|
||||||
|
.. _topics-testing-code-coverage:
|
||||||
|
|
||||||
|
Integration with coverage.py
|
||||||
|
============================
|
||||||
|
|
||||||
|
Code coverage describes how much source code has been tested. It shows which
|
||||||
|
parts of your code are being exercised by tests and which are not. It's an
|
||||||
|
important part of testing applications, so it's strongly recommended to check
|
||||||
|
the coverage of your tests.
|
||||||
|
|
||||||
|
Django can be easily integrated with `coverage.py`_, a tool for measuring code
|
||||||
|
coverage of Python programs. First, `install coverage.py`_. Next, run the
|
||||||
|
following from your project folder containing ``manage.py``::
|
||||||
|
|
||||||
|
coverage run --source='.' manage.py test myapp
|
||||||
|
|
||||||
|
This runs your tests and collects coverage data of the executed files in your
|
||||||
|
project. You can see a report of this data by typing following command::
|
||||||
|
|
||||||
|
coverage report
|
||||||
|
|
||||||
|
Note that some Django code was executed while running tests, but it is not
|
||||||
|
listed here because of the ``source`` flag passed to the previous command.
|
||||||
|
|
||||||
|
For more options like annotated HTML listings detailing missed lines, see the
|
||||||
|
`coverage.py`_ docs.
|
||||||
|
|
||||||
|
.. _coverage.py: http://nedbatchelder.com/code/coverage/
|
||||||
|
.. _install coverage.py: http://pypi.python.org/pypi/coverage
|
|
@ -0,0 +1,81 @@
|
||||||
|
===================
|
||||||
|
Django and doctests
|
||||||
|
===================
|
||||||
|
|
||||||
|
Doctests use Python's standard :mod:`doctest` module, which searches your
|
||||||
|
docstrings for statements that resemble a session of the Python interactive
|
||||||
|
interpreter. A full explanation of how :mod:`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 :ref:`fixtures
|
||||||
|
<topics-testing-fixtures>` 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 :mod:`doctest`, see the Python documentation.
|
|
@ -0,0 +1,111 @@
|
||||||
|
=================
|
||||||
|
Testing in Django
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
overview
|
||||||
|
doctests
|
||||||
|
advanced
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Unit tests v. doctests
|
||||||
|
======================
|
||||||
|
|
||||||
|
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 :class:`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]
|
||||||
|
|
||||||
|
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, :mod:`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 :mod:`unittest` framework will probably feel very familiar to
|
||||||
|
developers coming from Java. :mod:`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 :mod:`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 :mod:`unittest`.
|
||||||
|
|
||||||
|
Where to go from here
|
||||||
|
=====================
|
||||||
|
|
||||||
|
As unit tests are preferred in Django, we treat them in detail in the
|
||||||
|
:doc:`overview` document.
|
||||||
|
|
||||||
|
:doc:`doctests` describes Django-specific features when using doctests.
|
||||||
|
|
||||||
|
You can also use any *other* Python test framework, Django provides an API and
|
||||||
|
tools for that kind of integration. They are described in the
|
||||||
|
:ref:`other-testing-frameworks` section of :doc:`advanced`.
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue