<commit_before>=======================
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']
        },<commit_msg>[1.5.x] Fixed #20166 - Corrected TEST_DEPENDENCIES example in testing docs.<commit_after>=======================
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 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:`TEST_DEPENDENCIES` 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']
        },
{'fraction_non_alphanumeric': 0.12379724233706974, 'fraction_numerical': 0.0012895546076778098, 'mean_word_length': 2.9865559509687625, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4989221', 'n_tokens_mistral': 2605, 'n_tokens_neox': 2488, 'n_words': 1123}