浏览代码

Fixed #33422 -- Improved docs about isolating apps.

Christopher Adams 2 年之前
父节点
当前提交
90d2f9f416
共有 2 个文件被更改,包括 65 次插入61 次删除
  1. 2 61
      docs/internals/contributing/writing-code/unit-tests.txt
  2. 63 0
      docs/topics/testing/tools.txt

+ 2 - 61
docs/internals/contributing/writing-code/unit-tests.txt

@@ -522,25 +522,8 @@ Isolating model registration
 
 To avoid polluting the global :attr:`~django.apps.apps` registry and prevent
 unnecessary table creation, models defined in a test method should be bound to
-a temporary ``Apps`` instance::
-
-    from django.apps.registry import Apps
-    from django.db import models
-    from django.test import SimpleTestCase
-
-    class TestModelDefinition(SimpleTestCase):
-        def test_model_definition(self):
-            test_apps = Apps(['app_label'])
-
-            class TestModel(models.Model):
-                class Meta:
-                    apps = test_apps
-            ...
-
-.. function:: django.test.utils.isolate_apps(*app_labels, attr_name=None, kwarg_name=None)
-
-Since this pattern involves a lot of boilerplate, Django provides the
-:func:`~django.test.utils.isolate_apps` decorator. It's used like this::
+a temporary ``Apps`` instance. To do this, use the
+:func:`~django.test.utils.isolate_apps` decorator::
 
     from django.db import models
     from django.test import SimpleTestCase
@@ -581,45 +564,3 @@ Since this pattern involves a lot of boilerplate, Django provides the
                     class Meta:
                         app_label = 'other_app_label'
                 ...
-
-The decorator can also be applied to classes::
-
-    from django.db import models
-    from django.test import SimpleTestCase
-    from django.test.utils import isolate_apps
-
-    @isolate_apps('app_label')
-    class TestModelDefinition(SimpleTestCase):
-        def test_model_definition(self):
-            class TestModel(models.Model):
-                pass
-            ...
-
-The temporary ``Apps`` instance used to isolate model registration can be
-retrieved as an attribute when used as a class decorator by using the
-``attr_name`` parameter::
-
-    from django.db import models
-    from django.test import SimpleTestCase
-    from django.test.utils import isolate_apps
-
-    @isolate_apps('app_label', attr_name='apps')
-    class TestModelDefinition(SimpleTestCase):
-        def test_model_definition(self):
-            class TestModel(models.Model):
-                pass
-            self.assertIs(self.apps.get_model('app_label', 'TestModel'), TestModel)
-
-Or as an argument on the test method when used as a method decorator by using
-the ``kwarg_name`` parameter::
-
-    from django.db import models
-    from django.test import SimpleTestCase
-    from django.test.utils import isolate_apps
-
-    class TestModelDefinition(SimpleTestCase):
-        @isolate_apps('app_label', kwarg_name='apps')
-        def test_model_definition(self, apps):
-            class TestModel(models.Model):
-                pass
-            self.assertIs(apps.get_model('app_label', 'TestModel'), TestModel)

+ 63 - 0
docs/topics/testing/tools.txt

@@ -1398,6 +1398,69 @@ LOCALE_PATHS, LANGUAGE_CODE      Default translation and loaded translations
 MEDIA_ROOT, DEFAULT_FILE_STORAGE Default file storage
 ================================ ========================
 
+Isolating apps
+--------------
+
+.. function:: utils.isolate_apps(*app_labels, attr_name=None, kwarg_name=None)
+
+    Registers the models defined within a wrapped context into their own
+    isolated :attr:`~django.apps.apps` registry. This functionality is useful
+    when creating model classes for tests, as the classes will be cleanly
+    deleted afterward, and there is no risk of name collisions.
+
+    The app labels which the isolated registry should contain must be passed as
+    individual arguments. You can use ``isolate_apps()`` as a decorator or a
+    context manager. For example::
+
+        from django.db import models
+        from django.test import SimpleTestCase
+        from django.test.utils import isolate_apps
+
+        class MyModelTests(SimpleTestCase):
+
+            @isolate_apps("app_label")
+            def test_model_definition(self):
+                class TestModel(models.Model):
+                    pass
+                ...
+
+    … or::
+
+        with isolate_apps("app_label"):
+            class TestModel(models.Model):
+                pass
+            ...
+
+    The decorator form can also be applied to classes.
+
+    Two optional keyword arguments can be specified:
+
+    * ``attr_name``: attribute assigned the isolated registry if used as a
+      class decorator.
+    * ``kwarg_name``: keyword argument passing the isolated registry if used as
+      a function decorator.
+
+    The temporary ``Apps`` instance used to isolate model registration can be
+    retrieved as an attribute when used as a class decorator by using the
+    ``attr_name`` parameter::
+
+        @isolate_apps("app_label", attr_name="apps")
+        class TestModelDefinition(SimpleTestCase):
+            def test_model_definition(self):
+                class TestModel(models.Model):
+                    pass
+                self.assertIs(self.apps.get_model("app_label", "TestModel"), TestModel)
+
+    … or alternatively as an argument on the test method when used as a method
+    decorator by using the ``kwarg_name`` parameter::
+
+        class TestModelDefinition(SimpleTestCase):
+            @isolate_apps("app_label", kwarg_name="apps")
+            def test_model_definition(self, apps):
+                class TestModel(models.Model):
+                    pass
+                self.assertIs(apps.get_model("app_label", "TestModel"), TestModel)
+
 .. _emptying-test-outbox:
 
 Emptying the test outbox