django/docs/internals/contributing/writing-code/unit-tests.txt

226 lines
8.1 KiB
Plaintext

==========
Unit tests
==========
Django comes with a test suite of its own, in the ``tests`` directory of the
code base. It's our policy to make sure all tests pass at all times.
The tests cover:
* Models, the database API and everything else in core Django core (``tests/``),
* :ref:`contrib-apps` (``django/contrib/<app>/tests`` or ``tests/<app>_...``).
We appreciate any and all contributions to the test suite!
The Django tests all use the testing infrastructure that ships with Django for
testing applications. See :doc:`Testing Django applications
</topics/testing/overview>` for an explanation of how to write new tests.
.. _running-unit-tests:
Running the unit tests
----------------------
Quickstart
~~~~~~~~~~
Running the tests requires a Django settings module that defines the
databases to use. To make it easy to get started, Django provides and uses a
sample settings module that uses the SQLite database. To run the tests:
.. code-block:: bash
git clone git@github.com:django/django.git django-repo
cd django-repo/tests
PYTHONPATH=..:$PYTHONPATH ./runtests.py
.. versionchanged:: 1.7
Older versions of Django required specifying a settings file::
PYTHONPATH=..:$PYTHONPATH python ./runtests.py --settings=test_sqlite
``runtests.py`` now uses ``test_sqlite`` by default if settings aren't provided
through either ``--settings`` or :envvar:`DJANGO_SETTINGS_MODULE`.
You can avoid typing the ``PYTHONPATH`` bit each time by adding your Django
checkout to your ``PYTHONPATH`` or by installing the source checkout using pip.
See :ref:`installing-development-version`.
.. _running-unit-tests-settings:
Using another ``settings`` module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The included settings module allows you to run the test suite using
SQLite. If you want to test behavior using a different database (and
if you're proposing patches for Django, it's a good idea to test
across databases), you may need to define your own settings file.
To run the tests with different settings, ensure that the module is on your
``PYTHONPATH`` and pass the module with ``--settings``.
The :setting:`DATABASES` setting in any test settings module needs to define
two databases:
* A ``default`` database. This database should use the backend that
you want to use for primary testing
* A database with the alias ``other``. The ``other`` database is used to
establish that queries can be directed to different databases. As a result,
this database can use any backend you want. It doesn't need to use the same
backend as the ``default`` database (although it can use the same backend if
you want to). It cannot be the same database as the ``default``.
If you're using a backend that isn't SQLite, you will need to provide other
details for each database:
* The :setting:`USER` option needs to specify an existing user account
for the database.
* The :setting:`PASSWORD` option needs to provide the password for
the :setting:`USER` that has been specified.
* The :setting:`NAME` option must be the name of an existing database to
which the given user has permission to connect. The unit tests will not
touch this database; the test runner creates a new database whose name
is :setting:`NAME` prefixed with ``test_``, and this test database is
deleted when the tests are finished. This means your user account needs
permission to execute ``CREATE DATABASE``.
You will also need to ensure that your database uses UTF-8 as the default
character set. If your database server doesn't use UTF-8 as a default charset,
you will need to include a value for :setting:`TEST_CHARSET` in the settings
dictionary for the applicable database.
Running only some of the tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Django's entire test suite takes a while to run, and running every single test
could be redundant if, say, you just added a test to Django that you want to
run quickly without running everything else. You can run a subset of the unit
tests by appending the names of the test modules to ``runtests.py`` on the
command line.
For example, if you'd like to run tests only for generic relations and
internationalization, type:
.. code-block:: bash
./runtests.py --settings=path.to.settings generic_relations i18n
How do you find out the names of individual tests? Look in ``tests/`` — each
directory name there is the name of a test. Contrib app names are also valid
test names.
If you just want to run a particular class of tests, you can specify a list of
paths to individual test classes. For example, to run the ``TranslationTests``
of the ``i18n`` module, type:
.. code-block:: bash
./runtests.py --settings=path.to.settings i18n.tests.TranslationTests
Going beyond that, you can specify an individual test method like this:
.. code-block:: bash
./runtests.py --settings=path.to.settings i18n.tests.TranslationTests.test_lazy_objects
Running the Selenium tests
~~~~~~~~~~~~~~~~~~~~~~~~~~
Some admin tests require Selenium 2, Firefox and Python >= 2.6 to work via a
real Web browser. To allow those tests to run and not be skipped, you must
install the selenium_ package (version > 2.13) into your Python path and run
the tests with the ``--selenium`` option:
.. code-block:: bash
./runtests.py --settings=test_sqlite --selenium admin_inlines
.. _running-unit-tests-dependencies:
Running all the tests
~~~~~~~~~~~~~~~~~~~~~
If you want to run the full suite of tests, you'll need to install a number of
dependencies:
* bcrypt_
* docutils_
* Pillow_
* PyYAML_
* pytz_
* setuptools_
* memcached_, plus a :ref:`supported Python binding <memcached>`
* gettext_ (:ref:`gettext_on_windows`)
* selenium_
You can find these dependencies in `pip requirements files`_ inside the
``tests/requirements`` directory of the Django source tree and install them
like so::
pip install -r tests/requirements/py2.txt # Python 3: py3.txt
You can also install the database adapter(s) of your choice using
``oracle.txt``, ``mysql.txt``, or ``postgres.txt``.
If you want to test the memcached cache backend, you'll also need to define
a :setting:`CACHES` setting that points at your memcached instance.
To run the GeoDjango tests, you will need to :doc:`setup a spatial database
and install the Geospatial libraries</ref/contrib/gis/install/index>`.
Each of these dependencies is optional. If you're missing any of them, the
associated tests will be skipped.
.. _bcrypt: https://pypi.python.org/pypi/bcrypt
.. _docutils: https://pypi.python.org/pypi/docutils
.. _Pillow: https://pypi.python.org/pypi/Pillow/
.. _PyYAML: http://pyyaml.org/wiki/PyYAML
.. _pytz: https://pypi.python.org/pypi/pytz/
.. _setuptools: http://pypi.python.org/pypi/setuptools/
.. _memcached: http://memcached.org/
.. _gettext: http://www.gnu.org/software/gettext/manual/gettext.html
.. _selenium: http://pypi.python.org/pypi/selenium
.. _pip requirements files: http://www.pip-installer.org/en/latest/requirements.html
Code coverage
~~~~~~~~~~~~~
Contributors are encouraged to run coverage on the test suite to identify areas
that need additional tests. The coverage tool installation and use is described
in :ref:`testing code coverage<topics-testing-code-coverage>`.
To run coverage on the Django test suite using the standard test settings::
coverage run ./runtests.py --settings=test_sqlite
After running coverage, generate the html report by running::
coverage html
When running coverage for the Django tests, the included ``.coveragerc``
settings file defines ``coverage_html`` as the output directory for the report
and also excludes several directories not relevant to the results
(test code or external code included in Django).
.. _contrib-apps:
Contrib apps
------------
Tests for contrib apps go in their respective directories under
``django/contrib``, in a ``tests.py`` file. You can split the tests over
multiple modules by using a ``tests`` directory in the normal Python way.
For the tests to be found, a ``models.py`` file must exist, even if it's empty.
If you have URLs that need to be mapped, put them in ``tests/urls.py``.
To run tests for just one contrib app (e.g. ``auth``), use the same
method as above::
./runtests.py --settings=settings django.contrib.auth