diff options
| author | Simon Charette <charette.s@gmail.com> | 2015-11-17 00:33:18 -0500 |
|---|---|---|
| committer | Simon Charette <charette.s@gmail.com> | 2016-01-06 20:00:07 -0500 |
| commit | 7bb373e3097fe8e000e0bba005ff2dcfc18ab9a5 (patch) | |
| tree | 86ebceca4da5db2c13a16d8db82ac856540e5690 /docs/internals/contributing/writing-code | |
| parent | b2cddeaaf448234713f393749ceb1dbe22101f39 (diff) | |
Refs #25746 -- Added a test utility to isolate inlined model registration.
Thanks to Tim for the review.
Diffstat (limited to 'docs/internals/contributing/writing-code')
| -rw-r--r-- | docs/internals/contributing/writing-code/unit-tests.txt | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt index 75747b3110..31e795ee66 100644 --- a/docs/internals/contributing/writing-code/unit-tests.txt +++ b/docs/internals/contributing/writing-code/unit-tests.txt @@ -303,3 +303,117 @@ purpose. Support for running tests in parallel and the ``--parallel`` option were added. + +Tips for writing tests +---------------------- + +.. highlight:: python + +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) + +.. versionadded:: 1.10 + +Since this pattern involves a lot of boilerplate, Django provides the +:func:`~django.test.utils.isolate_apps` decorator. It's used like this:: + + from django.db import models + from django.test import SimpleTestCase + from django.test.utils import isolate_apps + + class TestModelDefinition(SimpleTestCase): + @isolate_apps('app_label') + def test_model_definition(self): + class TestModel(models.Model): + pass + ... + +.. admonition:: Setting ``app_label`` + + Models defined in a test method with no explicit + :attr:`~django.db.models.Options.app_label` are automatically assigned the + label of the app in which their test class is located. + + In order to make sure the models defined within the context of + :func:`~django.test.utils.isolate_apps` instances are correctly + installed, you should pass the set of targeted ``app_label`` as arguments: + + .. snippet:: + :filename: tests/app_label/tests.py + + from django.db import models + from django.test import SimpleTestCase + from django.test.utils import isolate_apps + + class TestModelDefinition(SimpleTestCase): + @isolate_apps('app_label', 'other_app_label') + def test_model_definition(self): + # This model automatically receives app_label='app_label' + class TestModel(models.Model): + pass + + class OtherAppModel(models.Model): + 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) |
