123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885 |
- =======================
- Advanced testing topics
- =======================
- The request factory
- ===================
- .. currentmodule:: django.test
- .. class:: RequestFactory
- The :class:`~django.test.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.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()`,
- :meth:`~Client.options()`, and :meth:`~Client.trace()`.
- * These methods accept all the same arguments *except* for
- ``follow``. 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.
- .. versionchanged:: 5.1
- The ``query_params`` parameter was added.
- Example
- -------
- The following is a unit test using the request factory::
- from django.contrib.auth.models import AnonymousUser, User
- from django.test import RequestFactory, TestCase
- from .views import MyView, my_view
- class SimpleTest(TestCase):
- def setUp(self):
- # Every test needs access to the request factory.
- self.factory = RequestFactory()
- self.user = User.objects.create_user(
- username="jacob", email="jacob@…", password="top_secret"
- )
- def test_details(self):
- # Create an instance of a GET request.
- request = self.factory.get("/customer/details")
- # Recall that middleware are not supported. You can simulate a
- # logged-in user by setting request.user manually.
- request.user = self.user
- # Or you can simulate an anonymous user by setting request.user to
- # an AnonymousUser instance.
- request.user = AnonymousUser()
- # Test my_view() as if it were deployed at /customer/details
- response = my_view(request)
- # Use this syntax for class-based views.
- response = MyView.as_view()(request)
- self.assertEqual(response.status_code, 200)
- AsyncRequestFactory
- -------------------
- .. class:: AsyncRequestFactory
- ``RequestFactory`` creates WSGI-like requests. If you want to create ASGI-like
- requests, including having a correct ASGI ``scope``, you can instead use
- ``django.test.AsyncRequestFactory``.
- This class is directly API-compatible with ``RequestFactory``, with the only
- difference being that it returns ``ASGIRequest`` instances rather than
- ``WSGIRequest`` instances. All of its methods are still synchronous callables.
- Arbitrary keyword arguments in ``defaults`` are added directly into the ASGI
- scope.
- .. versionchanged:: 5.1
- The ``query_params`` parameter was added.
- Testing class-based views
- =========================
- In order to test class-based views outside of the request/response cycle you
- must ensure that they are configured correctly, by calling
- :meth:`~django.views.generic.base.View.setup` after instantiation.
- For example, assuming the following class-based view:
- .. code-block:: python
- :caption: ``views.py``
- from django.views.generic import TemplateView
- class HomeView(TemplateView):
- template_name = "myapp/home.html"
- def get_context_data(self, **kwargs):
- kwargs["environment"] = "Production"
- return super().get_context_data(**kwargs)
- You may directly test the ``get_context_data()`` method by first instantiating
- the view, then passing a ``request`` to ``setup()``, before proceeding with
- your test's code:
- .. code-block:: python
- :caption: ``tests.py``
- from django.test import RequestFactory, TestCase
- from .views import HomeView
- class HomePageTest(TestCase):
- def test_environment_set_in_context(self):
- request = RequestFactory().get("/")
- view = HomeView()
- view.setup(request)
- context = view.get_context_data()
- self.assertIn("environment", context)
- .. _topics-testing-advanced-multiple-hosts:
- Tests and multiple host names
- =============================
- The :setting:`ALLOWED_HOSTS` setting is validated when running tests. This
- allows the test client to differentiate between internal and external URLs.
- Projects that support multitenancy or otherwise alter business logic based on
- the request's host and use custom host names in tests must include those hosts
- in :setting:`ALLOWED_HOSTS`.
- The first option to do so is to add the hosts to your settings file. For
- example, the test suite for docs.djangoproject.com includes the following::
- from django.test import TestCase
- class SearchFormTestCase(TestCase):
- def test_empty_get(self):
- response = self.client.get(
- "/en/dev/search/",
- headers={"host": "docs.djangoproject.dev:8000"},
- )
- self.assertEqual(response.status_code, 200)
- and the settings file includes a list of the domains supported by the project::
- ALLOWED_HOSTS = ["www.djangoproject.dev", "docs.djangoproject.dev", ...]
- Another option is to add the required hosts to :setting:`ALLOWED_HOSTS` using
- :meth:`~django.test.override_settings()` or
- :attr:`~django.test.SimpleTestCase.modify_settings()`. This option may be
- preferable in standalone apps that can't package their own settings file or
- for projects where the list of domains is not static (e.g., subdomains for
- multitenancy). For example, you could write a test for the domain
- ``http://otherserver/`` as follows::
- from django.test import TestCase, override_settings
- class MultiDomainTestCase(TestCase):
- @override_settings(ALLOWED_HOSTS=["otherserver"])
- def test_other_domain(self):
- response = self.client.get("http://otherserver/foo/bar/")
- Disabling :setting:`ALLOWED_HOSTS` checking (``ALLOWED_HOSTS = ['*']``) when
- running tests prevents the test client from raising a helpful error message if
- you follow a redirect to an external URL.
- .. _topics-testing-advanced-multidb:
- Tests and multiple databases
- ============================
- .. _topics-testing-primaryreplica:
- Testing primary/replica configurations
- --------------------------------------
- If you're testing a multiple database configuration with primary/replica
- (referred to as master/slave by some databases) 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 primary won't be seen on the
- replica.
- 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": "dbprimary",
- # ... plus some other settings
- },
- "replica": {
- "ENGINE": "django.db.backends.mysql",
- "NAME": "myproject",
- "HOST": "dbreplica",
- "TEST": {
- "MIRROR": "default",
- },
- # ... plus some other settings
- },
- }
- In this setup, we have two database servers: ``dbprimary``, described
- by the database alias ``default``, and ``dbreplica`` described by the
- alias ``replica``. As you might expect, ``dbreplica`` has been configured
- by the database administrator as a read replica of ``dbprimary``, so in
- normal activity, any write to ``default`` will appear on ``replica``.
- If Django created two independent test databases, this would break any
- tests that expected replication to occur. However, the ``replica``
- database has been configured as a test mirror (using the
- :setting:`MIRROR <TEST_MIRROR>` test setting), indicating that under
- testing, ``replica`` should be treated as a mirror of ``default``.
- When the test environment is configured, a test version of ``replica``
- will *not* be created. Instead the connection to ``replica``
- will be redirected to point at ``default``. As a result, writes to
- ``default`` will appear on ``replica`` -- but because they are actually
- the same database, not because there is data replication between the
- two databases. As this depends on transactions, the tests must use
- :class:`~django.test.TransactionTestCase` instead of
- :class:`~django.test.TestCase`.
- .. _topics-testing-creation-dependencies:
- Controlling creation order for test databases
- ---------------------------------------------
- By default, Django will assume all databases depend on the ``default``
- database and therefore 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:`DEPENDENCIES
- <TEST_DEPENDENCIES>` test setting. Consider the following (simplified)
- example database configuration::
- DATABASES = {
- "default": {
- # ... db settings
- "TEST": {
- "DEPENDENCIES": ["diamonds"],
- },
- },
- "diamonds": {
- # ... db settings
- "TEST": {
- "DEPENDENCIES": [],
- },
- },
- "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:`DEPENDENCIES
- <TEST_DEPENDENCIES>` definition, an
- :exc:`~django.core.exceptions.ImproperlyConfigured` exception will be raised.
- Advanced features of ``TransactionTestCase``
- ============================================
- .. attribute:: TransactionTestCase.available_apps
- .. warning::
- This attribute is a private API. It may be changed or removed without
- a deprecation period in the future, for instance to accommodate changes
- in application loading.
- It's used to optimize Django's own test suite, which contains hundreds
- of models but no relations between models in different applications.
- By default, ``available_apps`` is set to ``None``. After each test, Django
- calls :djadmin:`flush` to reset the database state. This empties all tables
- and emits the :data:`~django.db.models.signals.post_migrate` signal, which
- recreates one content type and four permissions for each model. This
- operation gets expensive proportionally to the number of models.
- Setting ``available_apps`` to a list of applications instructs Django to
- behave as if only the models from these applications were available. The
- behavior of ``TransactionTestCase`` changes as follows:
- - :data:`~django.db.models.signals.post_migrate` is fired before each
- test to create the content types and permissions for each model in
- available apps, in case they're missing.
- - After each test, Django empties only tables corresponding to models in
- available apps. However, at the database level, truncation may cascade to
- related models in unavailable apps. Furthermore
- :data:`~django.db.models.signals.post_migrate` isn't fired; it will be
- fired by the next ``TransactionTestCase``, after the correct set of
- applications is selected.
- Since the database isn't fully flushed, if a test creates instances of
- models not included in ``available_apps``, they will leak and they may
- cause unrelated tests to fail. Be careful with tests that use sessions;
- the default session engine stores them in the database.
- Since :data:`~django.db.models.signals.post_migrate` isn't emitted after
- flushing the database, its state after a ``TransactionTestCase`` isn't the
- same as after a ``TestCase``: it's missing the rows created by listeners
- to :data:`~django.db.models.signals.post_migrate`. Considering the
- :ref:`order in which tests are executed <order-of-tests>`, this isn't an
- issue, provided either all ``TransactionTestCase`` in a given test suite
- declare ``available_apps``, or none of them.
- ``available_apps`` is mandatory in Django's own test suite.
- .. attribute:: TransactionTestCase.reset_sequences
- Setting ``reset_sequences = True`` on a ``TransactionTestCase`` will make
- sure sequences are always reset before the test run::
- class TestsThatDependsOnPrimaryKeySequences(TransactionTestCase):
- reset_sequences = True
- def test_animal_pk(self):
- lion = Animal.objects.create(name="lion", sound="roar")
- # lion.pk is guaranteed to always be 1
- self.assertEqual(lion.pk, 1)
- Unless you are explicitly testing primary keys sequence numbers, it is
- recommended that you do not hard code primary key values in tests.
- Using ``reset_sequences = True`` will slow down the test, since the primary
- key reset is a relatively expensive database operation.
- .. _topics-testing-enforce-run-sequentially:
- Enforce running test classes sequentially
- =========================================
- If you have test classes that cannot be run in parallel (e.g. because they
- share a common resource), you can use ``django.test.testcases.SerializeMixin``
- to run them sequentially. This mixin uses a filesystem ``lockfile``.
- For example, you can use ``__file__`` to determine that all test classes in the
- same file that inherit from ``SerializeMixin`` will run sequentially::
- import os
- from django.test import TestCase
- from django.test.testcases import SerializeMixin
- class ImageTestCaseMixin(SerializeMixin):
- lockfile = __file__
- def setUp(self):
- self.filename = os.path.join(temp_storage_dir, "my_file.png")
- self.file = create_file(self.filename)
- class RemoveImageTests(ImageTestCaseMixin, TestCase):
- def test_remove_image(self):
- os.remove(self.filename)
- self.assertFalse(os.path.exists(self.filename))
- class ResizeImageTests(ImageTestCaseMixin, TestCase):
- def test_resize_image(self):
- resize_image(self.file, (48, 48))
- self.assertEqual(get_image_size(self.file), (48, 48))
- .. _testing-reusable-applications:
- Using the Django test runner to test reusable applications
- ==========================================================
- If you are writing a :doc:`reusable application </intro/reusable-apps>`
- you may want to use the Django test runner to run your own test suite
- and thus benefit from the Django testing infrastructure.
- A common practice is a *tests* directory next to the application code, with the
- following structure:
- .. code-block:: text
- runtests.py
- polls/
- __init__.py
- models.py
- ...
- tests/
- __init__.py
- models.py
- test_settings.py
- tests.py
- Let's take a look inside a couple of those files:
- .. code-block:: python
- :caption: ``runtests.py``
- #!/usr/bin/env python
- import os
- import sys
- import django
- from django.conf import settings
- from django.test.utils import get_runner
- if __name__ == "__main__":
- os.environ["DJANGO_SETTINGS_MODULE"] = "tests.test_settings"
- django.setup()
- TestRunner = get_runner(settings)
- test_runner = TestRunner()
- failures = test_runner.run_tests(["tests"])
- sys.exit(bool(failures))
- This is the script that you invoke to run the test suite. It sets up the
- Django environment, creates the test database and runs the tests.
- For the sake of clarity, this example contains only the bare minimum
- necessary to use the Django test runner. You may want to add
- command-line options for controlling verbosity, passing in specific test
- labels to run, etc.
- .. code-block:: python
- :caption: ``tests/test_settings.py``
- SECRET_KEY = "fake-key"
- INSTALLED_APPS = [
- "tests",
- ]
- This file contains the :doc:`Django settings </topics/settings>`
- required to run your app's tests.
- Again, this is a minimal example; your tests may require additional
- settings to run.
- Since the *tests* package is included in :setting:`INSTALLED_APPS` when
- running your tests, you can define test-only models in its ``models.py``
- file.
- .. _other-testing-frameworks:
- Using different testing frameworks
- ==================================
- Clearly, :mod:`unittest` is not the only Python testing framework. 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.runner.DiscoverRunner'``. This class defines the default Django
- testing behavior. This behavior involves:
- #. Performing global pre-test setup.
- #. Looking for tests in any file below the current directory whose name matches
- the pattern ``test*.py``.
- #. Creating the test databases.
- #. Running ``migrate`` to install models and initial data into the test
- databases.
- #. Running the :doc:`system checks </topics/checks>`.
- #. Running the tests that were 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.runner
- A test runner is a class defining a ``run_tests()`` method. Django ships
- with a ``DiscoverRunner`` 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 by ``run_tests()`` to set up, execute
- and tear down the test suite.
- .. class:: DiscoverRunner(pattern='test*.py', top_level=None, verbosity=1, interactive=True, failfast=False, keepdb=False, reverse=False, debug_mode=False, debug_sql=False, parallel=0, tags=None, exclude_tags=None, test_name_patterns=None, pdb=False, buffer=False, enable_faulthandler=True, timing=True, shuffle=False, logger=None, durations=None, **kwargs)
- ``DiscoverRunner`` will search for tests in any file matching ``pattern``.
- ``top_level`` can be used to specify the directory containing your
- top-level Python modules. Usually Django can figure this out automatically,
- so it's not necessary to specify this option. If specified, it should
- generally be the directory containing your ``manage.py`` file.
- ``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.
- If ``keepdb`` is ``True``, the test suite will use the existing database,
- or create one if necessary. If ``False``, a new database will be created,
- prompting the user to remove the existing one, if present.
- If ``reverse`` is ``True``, test cases will be executed in the opposite
- order. This could be useful to debug tests that aren't properly isolated
- and have side effects. :ref:`Grouping by test class <order-of-tests>` is
- preserved when using this option. This option can be used in conjunction
- with ``--shuffle`` to reverse the order for a particular random seed.
- ``debug_mode`` specifies what the :setting:`DEBUG` setting should be
- set to prior to running tests.
- ``parallel`` specifies the number of processes. If ``parallel`` is greater
- than ``1``, the test suite will run in ``parallel`` processes. If there are
- fewer test case classes than configured processes, Django will reduce the
- number of processes accordingly. Each process gets its own database. This
- option requires the third-party ``tblib`` package to display tracebacks
- correctly.
- ``tags`` can be used to specify a set of :ref:`tags for filtering tests
- <topics-tagging-tests>`. May be combined with ``exclude_tags``.
- ``exclude_tags`` can be used to specify a set of
- :ref:`tags for excluding tests <topics-tagging-tests>`. May be combined
- with ``tags``.
- If ``debug_sql`` is ``True``, failing test cases will output SQL queries
- logged to the :ref:`django.db.backends logger <django-db-logger>` as well
- as the traceback. If ``verbosity`` is ``2``, then queries in all tests are
- output.
- ``test_name_patterns`` can be used to specify a set of patterns for
- filtering test methods and classes by their names.
- If ``pdb`` is ``True``, a debugger (``pdb`` or ``ipdb``) will be spawned at
- each test error or failure.
- If ``buffer`` is ``True``, outputs from passing tests will be discarded.
- If ``enable_faulthandler`` is ``True``, :py:mod:`faulthandler` will be
- enabled.
- If ``timing`` is ``True``, test timings, including database setup and total
- run time, will be shown.
- If ``shuffle`` is an integer, test cases will be shuffled in a random order
- prior to execution, using the integer as a random seed. If ``shuffle`` is
- ``None``, the seed will be generated randomly. In both cases, the seed will
- be logged and set to ``self.shuffle_seed`` prior to running tests. This
- option can be used to help detect tests that aren't properly isolated.
- :ref:`Grouping by test class <order-of-tests>` is preserved when using this
- option.
- ``logger`` can be used to pass a Python :py:ref:`Logger object <logger>`.
- If provided, the logger will be used to log messages instead of printing to
- the console. The logger object will respect its logging level rather than
- the ``verbosity``.
- ``durations`` will show a list of the N slowest test cases. Setting this
- option to ``0`` will result in the duration for all tests being shown.
- Requires Python 3.12+.
- Django may, 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 ``DiscoverRunner`` or write your own test
- runner, ensure it accepts ``**kwargs``.
- Your test runner may also define additional command-line options.
- Create or override an ``add_arguments(cls, parser)`` class method and add
- custom arguments by calling ``parser.add_argument()`` inside the method, so
- that the :djadmin:`test` command will be able to use those arguments.
- Attributes
- ~~~~~~~~~~
- .. attribute:: DiscoverRunner.test_suite
- The class used to build the test suite. By default it is set to
- ``unittest.TestSuite``. This can be overridden if you wish to implement
- different logic for collecting tests.
- .. attribute:: DiscoverRunner.test_runner
- This is the class of the low-level test runner which is used to execute
- the individual tests and format the results. By default it is set to
- ``unittest.TextTestRunner``. Despite the unfortunate similarity in
- naming conventions, this is not the same type of class as
- ``DiscoverRunner``, which covers a broader set of responsibilities. You
- can override this attribute to modify the way tests are run and reported.
- .. attribute:: DiscoverRunner.test_loader
- This is the class that loads tests, whether from TestCases or modules or
- otherwise and bundles them into test suites for the runner to execute.
- By default it is set to ``unittest.defaultTestLoader``. You can override
- this attribute if your tests are going to be loaded in unusual ways.
- Methods
- ~~~~~~~
- .. method:: DiscoverRunner.run_tests(test_labels, **kwargs)
- Run the test suite.
- ``test_labels`` allows you to specify which tests to run and supports
- several formats (see :meth:`DiscoverRunner.build_suite` for a list of
- supported formats).
- This method should return the number of tests that failed.
- .. classmethod:: DiscoverRunner.add_arguments(parser)
- Override this class method to add custom arguments accepted by the
- :djadmin:`test` management command. See
- :py:meth:`argparse.ArgumentParser.add_argument()` for details about adding
- arguments to a parser.
- .. method:: DiscoverRunner.setup_test_environment(**kwargs)
- Sets up the test environment by calling
- :func:`~django.test.utils.setup_test_environment` and setting
- :setting:`DEBUG` to ``self.debug_mode`` (defaults to ``False``).
- .. method:: DiscoverRunner.build_suite(test_labels=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 four forms:
- * ``path.to.test_module.TestCase.test_method`` -- Run a single test method
- in a test case class.
- * ``path.to.test_module.TestCase`` -- Run all the test methods in a test
- case.
- * ``path.to.module`` -- Search for and run all tests in the named Python
- package or module.
- * ``path/to/directory`` -- Search for and run all tests below the named
- directory.
- If ``test_labels`` has a value of ``None``, the test runner will search for
- tests in all files below the current directory whose names match its
- ``pattern`` (see above).
- Returns a ``TestSuite`` instance ready to be run.
- .. method:: DiscoverRunner.setup_databases(**kwargs)
- Creates the test databases by calling
- :func:`~django.test.utils.setup_databases`.
- .. method:: DiscoverRunner.run_checks(databases)
- Runs the :doc:`system checks </topics/checks>` on the test ``databases``.
- .. method:: DiscoverRunner.run_suite(suite, **kwargs)
- Runs the test suite.
- Returns the result produced by the running the test suite.
- .. method:: DiscoverRunner.get_test_runner_kwargs()
- Returns the keyword arguments to instantiate the
- ``DiscoverRunner.test_runner`` with.
- .. method:: DiscoverRunner.teardown_databases(old_config, **kwargs)
- Destroys the test databases, restoring pre-test conditions by calling
- :func:`~django.test.utils.teardown_databases`.
- .. method:: DiscoverRunner.teardown_test_environment(**kwargs)
- Restores the pre-test environment.
- .. method:: DiscoverRunner.suite_result(suite, result, **kwargs)
- Computes and returns a return code based on a test suite, and the result
- from that test suite.
- .. method:: DiscoverRunner.log(msg, level=None)
- If a ``logger`` is set, logs the message at the given integer
- `logging level`_ (e.g. ``logging.DEBUG``, ``logging.INFO``, or
- ``logging.WARNING``). Otherwise, the message is printed to the console,
- respecting the current ``verbosity``. For example, no message will be
- printed if the ``verbosity`` is 0, ``INFO`` and above will be printed if
- the ``verbosity`` is at least 1, and ``DEBUG`` will be printed if it is at
- least 2. The ``level`` defaults to ``logging.INFO``.
- .. _`logging level`: https://docs.python.org/3/library/logging.html#levels
- Testing utilities
- -----------------
- ``django.test.utils``
- ~~~~~~~~~~~~~~~~~~~~~
- .. 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(debug=None)
- Performs global pre-test setup, such as installing instrumentation for the
- template rendering system and setting up the dummy email outbox.
- If ``debug`` isn't ``None``, the :setting:`DEBUG` setting is updated to its
- value.
- .. function:: teardown_test_environment()
- Performs global post-test teardown, such as removing instrumentation from
- the template system and restoring normal email services.
- .. function:: setup_databases(verbosity, interactive, *, time_keeper=None, keepdb=False, debug_sql=False, parallel=0, aliases=None, serialized_aliases=None, **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
- :func:`teardown_databases` function at the conclusion of testing.
- The ``aliases`` argument determines which :setting:`DATABASES` aliases test
- databases should be set up for. If it's not provided, it defaults to all of
- :setting:`DATABASES` aliases.
- The ``serialized_aliases`` argument determines what subset of ``aliases``
- test databases should have their state serialized to allow usage of the
- :ref:`serialized_rollback <test-case-serialized-rollback>` feature. If
- it's not provided, it defaults to ``aliases``.
- .. function:: teardown_databases(old_config, parallel=0, keepdb=False)
- 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's the return value of the
- :meth:`setup_databases` method.
- ``django.db.connection.creation``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- .. currentmodule:: django.db.connection.creation
- The creation module of the database backend also provides some utilities that
- can be useful during testing.
- .. function:: create_test_db(verbosity=1, autoclobber=False, serialize=True, keepdb=False)
- Creates a new test database and runs ``migrate`` 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.
- ``serialize`` determines if Django serializes the database into an
- in-memory JSON string before running tests (used to restore the database
- state between tests if you don't have transactions). You can set this to
- ``False`` to speed up creation time if you don't have any test classes
- with :ref:`serialized_rollback=True <test-case-serialized-rollback>`.
- ``keepdb`` determines if the test run should use an existing
- database, or create a new one. If ``True``, the existing
- database will be used, or created if not present. If ``False``,
- a new database will be created, prompting the user to remove
- the existing one, if present.
- 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, keepdb=False)
- 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.runner.DiscoverRunner`.
- If the ``keepdb`` argument is ``True``, then the connection to the
- database will be closed, but the database will not be destroyed.
- .. _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 :pypi:`coverage`. Next, run the
- following from your project folder containing ``manage.py``:
- .. code-block:: shell
- 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:
- .. code-block:: shell
- 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: https://coverage.readthedocs.io/
|