diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index 9170ff83a830..1bf6ce538355 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -894,6 +894,8 @@ fields: changed to* ``fields.E010`` *in Django 3.1*. * **postgres.W004**: Base field for array has warnings: ... +.. _sites-system-checks: + ``sites`` --------- diff --git a/docs/ref/contrib/gis/geos.txt b/docs/ref/contrib/gis/geos.txt index 471103bf974e..fed384742477 100644 --- a/docs/ref/contrib/gis/geos.txt +++ b/docs/ref/contrib/gis/geos.txt @@ -325,8 +325,7 @@ Properties is simple if and only if it does not intersect itself (except at boundary points). For example, a :class:`LineString` object is not simple if it intersects itself. Thus, :class:`LinearRing` and :class:`Polygon` objects - are always simple because they do cannot intersect themselves, by - definition. + are always simple because they cannot intersect themselves, by definition. .. attribute:: GEOSGeometry.valid diff --git a/docs/topics/checks.txt b/docs/topics/checks.txt index 3b3a02eef08f..9a91ceb46903 100644 --- a/docs/topics/checks.txt +++ b/docs/topics/checks.txt @@ -214,3 +214,67 @@ Messages are comparable. That allows you to easily write tests:: ) ] self.assertEqual(errors, expected_errors) + +Writing integration tests +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Given the need to register certain checks when the application loads, it can be +useful to test their integration within the system checks framework. This can +be accomplished by using the :func:`~django.core.management.call_command` +function. + +For example, this test demonstrates that the :setting:`SITE_ID` setting must be +an integer, a built-in :ref:`check from the sites framework +`:: + + from django.core.management import call_command + from django.core.management.base import SystemCheckError + from django.test import SimpleTestCase, modify_settings, override_settings + + + class SystemCheckIntegrationTest(SimpleTestCase): + @override_settings(SITE_ID="non_integer") + @modify_settings(INSTALLED_APPS={"prepend": "django.contrib.sites"}) + def test_non_integer_site_id(self): + message = "(sites.E101) The SITE_ID setting must be an integer." + with self.assertRaisesMessage(SystemCheckError, message): + call_command("check") + +Consider the following check which issues a warning on deployment if a custom +setting named ``ENABLE_ANALYTICS`` is not set to ``True``:: + + from django.conf import settings + from django.core.checks import Warning, register + + + @register("myapp", deploy=True) + def check_enable_analytics_is_true_on_deploy(app_configs, **kwargs): + errors = [] + if getattr(settings, "ENABLE_ANALYTICS", None) is not True: + errors.append( + Warning( + "The ENABLE_ANALYTICS setting should be set to True in deployment.", + id="myapp.W001", + ) + ) + return errors + +Given that this check will not raise a ``SystemCheckError``, the presence of +the warning message in the ``stderr`` output can be asserted like so:: + + from io import StringIO + + from django.core.management import call_command + from django.test import SimpleTestCase, override_settings + + + class EnableAnalyticsDeploymentCheckTest(SimpleTestCase): + @override_settings(ENABLE_ANALYTICS=None) + def test_when_set_to_none(self): + stderr = StringIO() + call_command("check", "-t", "myapp", "--deploy", stderr=stderr) + message = ( + "(myapp.W001) The ENABLE_ANALYTICS setting should be set " + "to True in deployment." + ) + self.assertIn(message, stderr.getvalue()) diff --git a/docs/topics/db/fixtures.txt b/docs/topics/db/fixtures.txt index 4db6de89eb5e..ab6ade9ca9e6 100644 --- a/docs/topics/db/fixtures.txt +++ b/docs/topics/db/fixtures.txt @@ -19,62 +19,104 @@ How to produce a fixture? ========================= Fixtures can be generated by :djadmin:`manage.py dumpdata `. It's -also possible to generate custom fixtures by directly using -:doc:`serialization documentation ` tools or even by -handwriting them. +also possible to generate custom fixtures by directly using :doc:`serialization +tools ` or even by handwriting them. -What to use a fixture for? -========================== +How to use a fixture? +===================== Fixtures can be used to pre-populate database with data for -:ref:`tests ` or to provide some :ref:`initial data -`. +:ref:`tests `: + +.. code-block:: python + + class MyTestCase(TestCase): + fixtures = ["fixture-label"] + +or to provide some :ref:`initial data ` using the +:djadmin:`loaddata` command: + +.. code-block:: shell + + django-admin loaddata + Where Django looks for fixtures? ================================ -Django will search in three locations for fixtures: +Django will search in these locations for fixtures: 1. In the ``fixtures`` directory of every installed application -2. In any directory named in the :setting:`FIXTURE_DIRS` setting +2. In any directory listed in the :setting:`FIXTURE_DIRS` setting 3. In the literal path named by the fixture Django will load any and all fixtures it finds in these locations that match -the provided fixture names. - -If the named fixture has a file extension, only fixtures of that type -will be loaded. For example: +the provided fixture names. If the named fixture has a file extension, only +fixtures of that type will be loaded. For example: .. code-block:: shell django-admin loaddata mydata.json -would only load JSON fixtures called ``mydata``. The fixture extension -must correspond to the registered name of a +would only load JSON fixtures called ``mydata``. The fixture extension must +correspond to the registered name of a :ref:`serializer ` (e.g., ``json`` or ``xml``). -If you omit the extensions, Django will search all available fixture types -for a matching fixture. For example: +If you omit the extensions, Django will search all available fixture types for +a matching fixture. For example: .. code-block:: shell django-admin loaddata mydata would look for any fixture of any fixture type called ``mydata``. If a fixture -directory contained ``mydata.json``, that fixture would be loaded -as a JSON fixture. +directory contained ``mydata.json``, that fixture would be loaded as a JSON +fixture. -The fixtures that are named can include directory components. These -directories will be included in the search path. For example: +The fixtures that are named can include directory components. These directories +will be included in the search path. For example: .. code-block:: shell django-admin loaddata foo/bar/mydata.json would search ``/fixtures/foo/bar/mydata.json`` for each installed -application, ``/foo/bar/mydata.json`` for each directory in +application, ``/foo/bar/mydata.json`` for each directory in :setting:`FIXTURE_DIRS`, and the literal path ``foo/bar/mydata.json``. +Fixtures loading order +---------------------- + +Multiple fixtures can be specified in the same invocation. For example: + +.. code-block:: shell + + manage.py loaddata mammals birds insects + +or in a test case class: + +.. code-block:: python + + class AnimalTestCase(TestCase): + fixtures = ["mammals", "birds", "insects"] + +The order in which fixtures are loaded follows the order in which they are +listed, whether it's when using the management command or when listing them in +the test case class as shown above. + +In these examples, all the fixtures named ``mammals`` from all applications (in +the order in which applications are defined in :setting:`INSTALLED_APPS`) will +be loaded first. Subsequently, all the ``birds`` fixtures will be loaded, +followed by all the ``insects`` fixtures. + +Be aware that if the database backend supports row-level constraints, these +constraints will be checked at the end of the transaction. Any relationships +across fixtures may result in a load error if the database configuration does +not support deferred constraint checking (refer to the `MySQL`_ docs for an +example). + +.. _MySQL: https://dev.mysql.com/doc/refman/en/constraint-foreign-key.html + How fixtures are saved to the database? ======================================= @@ -124,13 +166,7 @@ You could also write a decorator to encapsulate this logic:: ... Just be aware that this logic will disable the signals whenever fixtures are -deserialized, not just during ``loaddata``. - -Note that the order in which fixture files are processed is undefined. However, -all fixture data is installed as a single transaction, so data in -one fixture can reference data in another fixture. If the database backend -supports row-level constraints, these constraints will be checked at the -end of the transaction. +deserialized, not just during :djadmin:`loaddata`. Compressed fixtures =================== @@ -146,11 +182,10 @@ would look for any of ``mydata.json``, ``mydata.json.zip``, ``mydata.json.gz``, ``mydata.json.bz2``, ``mydata.json.lzma``, or ``mydata.json.xz``. The first file contained within a compressed archive is used. -Note that if two fixtures with the same name but different -fixture type are discovered (for example, if ``mydata.json`` and -``mydata.xml.gz`` were found in the same fixture directory), fixture -installation will be aborted, and any data installed in the call to -``loaddata`` will be removed from the database. +Note that if two fixtures with the same name but different fixture type are +discovered (for example, if ``mydata.json`` and ``mydata.xml.gz`` were found in +the same fixture directory), fixture installation will be aborted, and any data +installed in the call to :djadmin:`loaddata` will be removed from the database. .. admonition:: MySQL with MyISAM and fixtures diff --git a/tests/backends/base/test_base.py b/tests/backends/base/test_base.py index ada2cc33c909..9f2fa4e57690 100644 --- a/tests/backends/base/test_base.py +++ b/tests/backends/base/test_base.py @@ -62,7 +62,7 @@ def test_check_database_version_supported_with_none_as_database_version(self): class DatabaseWrapperLoggingTests(TransactionTestCase): - available_apps = [] + available_apps = ["backends"] @override_settings(DEBUG=True) def test_commit_debug_log(self):