Răsfoiți Sursa

Fixed #21598 -- cleaned up template loader overrides in tests

- Template loader overriding is managed with contexts.
- The test loader is a class (function based loaders entered deprecation timeline
  in 1.4).
- Template loader overrider that overrides with test loader added.
Unai Zalakain 11 ani în urmă
părinte
comite
4dc4d12e27

+ 89 - 24
django/test/utils.py

@@ -146,42 +146,107 @@ def get_runner(settings, test_runner_class=None):
     return test_runner
 
 
-def setup_test_template_loader(templates_dict, use_cached_loader=False):
+class override_template_loaders(object):
     """
-    Changes Django to only find templates from within a dictionary (where each
-    key is the template name and each value is the corresponding template
-    content to return).
+    Acts as a function decorator, context manager or start/end manager and
+    override the template loaders. It could be used in the following ways:
 
-    Use meth:`restore_template_loaders` to restore the original loaders.
+    @override_template_loaders(SomeLoader())
+    def test_function(self):
+        ...
+
+    with override_template_loaders(SomeLoader(), OtherLoader()) as loaders:
+        ...
+
+    loaders = override_template_loaders.override(SomeLoader())
+    ...
+    override_template_loaders.restore()
     """
-    if hasattr(loader, RESTORE_LOADERS_ATTR):
-        raise Exception("loader.%s already exists" % RESTORE_LOADERS_ATTR)
+    def __init__(self, *loaders):
+        self.loaders = loaders
+        self.old_loaders = []
+
+    def __enter__(self):
+        self.old_loaders = loader.template_source_loaders
+        loader.template_source_loaders = self.loaders
+        return self.loaders
+
+    def __exit__(self, type, value, traceback):
+        loader.template_source_loaders = self.old_loaders
+
+    def __call__(self, test_func):
+        @wraps(test_func)
+        def inner(*args, **kwargs):
+            with self:
+                return test_func(*args, **kwargs)
+        return inner
+
+    @classmethod
+    def override(cls, *loaders):
+        if hasattr(loader, RESTORE_LOADERS_ATTR):
+            raise Exception("loader.%s already exists" % RESTORE_LOADERS_ATTR)
+        setattr(loader, RESTORE_LOADERS_ATTR, loader.template_source_loaders)
+        loader.template_source_loaders = loaders
+        return loaders
 
-    def test_template_loader(template_name, template_dirs=None):
-        "A custom template loader that loads templates from a dictionary."
+    @classmethod
+    def restore(cls):
+        loader.template_source_loaders = getattr(loader, RESTORE_LOADERS_ATTR)
+        delattr(loader, RESTORE_LOADERS_ATTR)
+
+
+class TestTemplateLoader(loader.BaseLoader):
+    "A custom template loader that loads templates from a dictionary."
+    is_usable = True
+
+    def __init__(self, templates_dict):
+        self.templates_dict = templates_dict
+
+    def load_template_source(self, template_name, template_dirs=None,
+                             skip_template=None):
         try:
-            return (templates_dict[template_name], "test:%s" % template_name)
+            return (self.templates_dict[template_name],
+                    "test:%s" % template_name)
         except KeyError:
             raise TemplateDoesNotExist(template_name)
 
-    if use_cached_loader:
-        template_loader = cached.Loader(('test_template_loader',))
-        template_loader._cached_loaders = (test_template_loader,)
-    else:
-        template_loader = test_template_loader
 
-    setattr(loader, RESTORE_LOADERS_ATTR, loader.template_source_loaders)
-    loader.template_source_loaders = (template_loader,)
-    return template_loader
+class override_with_test_loader(override_template_loaders):
+    """
+    Acts as a function decorator, context manager or start/end manager and
+    override the template loaders with the test loader. It could be used in the
+    following ways:
 
+    @override_with_test_loader(templates_dict, use_cached_loader=True)
+    def test_function(self):
+        ...
 
-def restore_template_loaders():
-    """
-    Restores the original template loaders after
-    :meth:`setup_test_template_loader` has been run.
+    with override_with_test_loader(templates_dict) as test_loader:
+        ...
+
+    test_loader = override_with_test_loader.override(templates_dict)
+    ...
+    override_with_test_loader.restore()
     """
-    loader.template_source_loaders = getattr(loader, RESTORE_LOADERS_ATTR)
-    delattr(loader, RESTORE_LOADERS_ATTR)
+
+    def __init__(self, templates_dict, use_cached_loader=False):
+        self.loader = self._get_loader(templates_dict, use_cached_loader)
+        super(override_with_test_loader, self).__init__(self.loader)
+
+    def __enter__(self):
+        return super(override_with_test_loader, self).__enter__()[0]
+
+    @classmethod
+    def override(cls, templates_dict, use_cached_loader=False):
+        loader = cls._get_loader(templates_dict, use_cached_loader)
+        return super(override_with_test_loader, cls).override(loader)[0]
+
+    @classmethod
+    def _get_loader(cls, templates_dict, use_cached_loader=False):
+        if use_cached_loader:
+            loader = cached.Loader(('TestTemplateLoader',))
+            loader._cached_loaders = TestTemplateLoader(templates_dict)
+        return TestTemplateLoader(templates_dict)
 
 
 class override_settings(object):

+ 125 - 156
tests/template_tests/tests.py

@@ -15,8 +15,8 @@ from django.template import (base as template_base, loader, Context,
     RequestContext, Template, TemplateSyntaxError)
 from django.template.loaders import app_directories, filesystem, cached
 from django.test import RequestFactory, TestCase
-from django.test.utils import (setup_test_template_loader,
-    restore_template_loaders, override_settings, extend_sys_path)
+from django.test.utils import (override_settings, override_template_loaders,
+                               override_with_test_loader, extend_sys_path)
 from django.utils.deprecation import RemovedInDjango19Warning, RemovedInDjango20Warning
 from django.utils.encoding import python_2_unicode_compatible
 from django.utils.formats import date_format
@@ -208,42 +208,36 @@ class TemplateLoaderTests(TestCase):
             test_template_sources('/DIR1/index.HTML', template_dirs,
                                   ['/DIR1/index.HTML'])
 
+    @override_template_loaders(filesystem.Loader())
     # Turn TEMPLATE_DEBUG on, so that the origin file name will be kept with
     # the compiled templates.
     @override_settings(TEMPLATE_DEBUG=True)
     def test_loader_debug_origin(self):
-        old_loaders = loader.template_source_loaders
-
-        try:
-            loader.template_source_loaders = (filesystem.Loader(),)
-
-            # We rely on the fact that runtests.py sets up TEMPLATE_DIRS to
-            # point to a directory containing a login.html file. Also that
-            # the file system and app directories loaders both inherit the
-            # load_template method from the BaseLoader class, so we only need
-            # to test one of them.
-            load_name = 'login.html'
-            template = loader.get_template(load_name)
-            template_name = template.nodelist[0].source[0].name
-            self.assertTrue(template_name.endswith(load_name),
-                'Template loaded by filesystem loader has incorrect name for debug page: %s' % template_name)
-
-            # Also test the cached loader, since it overrides load_template
-            cache_loader = cached.Loader(('',))
-            cache_loader._cached_loaders = loader.template_source_loaders
-            loader.template_source_loaders = (cache_loader,)
-
-            template = loader.get_template(load_name)
-            template_name = template.nodelist[0].source[0].name
-            self.assertTrue(template_name.endswith(load_name),
-                'Template loaded through cached loader has incorrect name for debug page: %s' % template_name)
-
-            template = loader.get_template(load_name)
-            template_name = template.nodelist[0].source[0].name
-            self.assertTrue(template_name.endswith(load_name),
-                'Cached template loaded through cached loader has incorrect name for debug page: %s' % template_name)
-        finally:
-            loader.template_source_loaders = old_loaders
+        # We rely on the fact that runtests.py sets up TEMPLATE_DIRS to
+        # point to a directory containing a login.html file. Also that
+        # the file system and app directories loaders both inherit the
+        # load_template method from the BaseLoader class, so we only need
+        # to test one of them.
+        load_name = 'login.html'
+        template = loader.get_template(load_name)
+        template_name = template.nodelist[0].source[0].name
+        self.assertTrue(template_name.endswith(load_name),
+            'Template loaded by filesystem loader has incorrect name for debug page: %s' % template_name)
+
+        # Also test the cached loader, since it overrides load_template
+        cache_loader = cached.Loader(('',))
+        cache_loader._cached_loaders = loader.template_source_loaders
+        loader.template_source_loaders = (cache_loader,)
+
+        template = loader.get_template(load_name)
+        template_name = template.nodelist[0].source[0].name
+        self.assertTrue(template_name.endswith(load_name),
+            'Template loaded through cached loader has incorrect name for debug page: %s' % template_name)
+
+        template = loader.get_template(load_name)
+        template_name = template.nodelist[0].source[0].name
+        self.assertTrue(template_name.endswith(load_name),
+            'Cached template loaded through cached loader has incorrect name for debug page: %s' % template_name)
 
     def test_loader_origin(self):
         with self.settings(TEMPLATE_DEBUG=True):
@@ -262,33 +256,31 @@ class TemplateLoaderTests(TestCase):
     # TEMPLATE_DEBUG must be true, otherwise the exception raised
     # during {% include %} processing will be suppressed.
     @override_settings(TEMPLATE_DEBUG=True)
+    # Test the base loader class via the app loader. load_template
+    # from base is used by all shipped loaders excepting cached,
+    # which has its own test.
+    @override_template_loaders(app_directories.Loader())
     def test_include_missing_template(self):
         """
         Tests that the correct template is identified as not existing
         when {% include %} specifies a template that does not exist.
         """
-        old_loaders = loader.template_source_loaders
-
+        load_name = 'test_include_error.html'
+        r = None
         try:
-            # Test the base loader class via the app loader. load_template
-            # from base is used by all shipped loaders excepting cached,
-            # which has its own test.
-            loader.template_source_loaders = (app_directories.Loader(),)
-
-            load_name = 'test_include_error.html'
-            r = None
-            try:
-                tmpl = loader.select_template([load_name])
-                r = tmpl.render(template.Context({}))
-            except template.TemplateDoesNotExist as e:
-                self.assertEqual(e.args[0], 'missing.html')
-            self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
-        finally:
-            loader.template_source_loaders = old_loaders
+            tmpl = loader.select_template([load_name])
+            r = tmpl.render(template.Context({}))
+        except template.TemplateDoesNotExist as e:
+            self.assertEqual(e.args[0], 'missing.html')
+        self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
 
     # TEMPLATE_DEBUG must be true, otherwise the exception raised
     # during {% include %} processing will be suppressed.
     @override_settings(TEMPLATE_DEBUG=True)
+    # Test the base loader class via the app loader. load_template
+    # from base is used by all shipped loaders excepting cached,
+    # which has its own test.
+    @override_template_loaders(app_directories.Loader())
     def test_extends_include_missing_baseloader(self):
         """
         Tests that the correct template is identified as not existing
@@ -296,24 +288,14 @@ class TemplateLoaderTests(TestCase):
         that template has an {% include %} of something that does not
         exist. See #12787.
         """
-        old_loaders = loader.template_source_loaders
-
+        load_name = 'test_extends_error.html'
+        tmpl = loader.get_template(load_name)
+        r = None
         try:
-            # Test the base loader class via the app loader. load_template
-            # from base is used by all shipped loaders excepting cached,
-            # which has its own test.
-            loader.template_source_loaders = (app_directories.Loader(),)
-
-            load_name = 'test_extends_error.html'
-            tmpl = loader.get_template(load_name)
-            r = None
-            try:
-                r = tmpl.render(template.Context({}))
-            except template.TemplateDoesNotExist as e:
-                self.assertEqual(e.args[0], 'missing.html')
-            self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
-        finally:
-            loader.template_source_loaders = old_loaders
+            r = tmpl.render(template.Context({}))
+        except template.TemplateDoesNotExist as e:
+            self.assertEqual(e.args[0], 'missing.html')
+        self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
 
     @override_settings(TEMPLATE_DEBUG=True)
     def test_extends_include_missing_cachedloader(self):
@@ -321,14 +303,9 @@ class TemplateLoaderTests(TestCase):
         Same as test_extends_include_missing_baseloader, only tests
         behavior of the cached loader instead of BaseLoader.
         """
-
-        old_loaders = loader.template_source_loaders
-
-        try:
-            cache_loader = cached.Loader(('',))
-            cache_loader._cached_loaders = (app_directories.Loader(),)
-            loader.template_source_loaders = (cache_loader,)
-
+        cache_loader = cached.Loader(('',))
+        cache_loader._cached_loaders = (app_directories.Loader(),)
+        with override_template_loaders(cache_loader,):
             load_name = 'test_extends_error.html'
             tmpl = loader.get_template(load_name)
             r = None
@@ -346,8 +323,6 @@ class TemplateLoaderTests(TestCase):
             except template.TemplateDoesNotExist as e:
                 self.assertEqual(e.args[0], 'missing.html')
             self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
-        finally:
-            loader.template_source_loaders = old_loaders
 
     def test_include_template_argument(self):
         """
@@ -544,89 +519,83 @@ class TemplateTests(TestCase):
 
         template_tests.update(filter_tests)
 
-        cache_loader = setup_test_template_loader(
-            dict((name, t[0]) for name, t in six.iteritems(template_tests)),
-            use_cached_loader=True,
-        )
+        templates = dict((name, t[0]) for name, t in six.iteritems(template_tests))
+        with override_with_test_loader(templates, use_cached_loader=True) as cache_loader:
+            failures = []
+            tests = sorted(template_tests.items())
 
-        failures = []
-        tests = sorted(template_tests.items())
-
-        # Set TEMPLATE_STRING_IF_INVALID to a known string.
-        expected_invalid_str = 'INVALID'
-
-        # Warm the URL reversing cache. This ensures we don't pay the cost
-        # warming the cache during one of the tests.
-        urlresolvers.reverse('template_tests.views.client_action',
-                             kwargs={'id': 0, 'action': "update"})
-
-        for name, vals in tests:
-            if isinstance(vals[2], tuple):
-                normal_string_result = vals[2][0]
-                invalid_string_result = vals[2][1]
-
-                if isinstance(invalid_string_result, tuple):
-                    expected_invalid_str = 'INVALID %s'
-                    invalid_string_result = invalid_string_result[0] % invalid_string_result[1]
-                    template_base.invalid_var_format_string = True
-
-                try:
-                    template_debug_result = vals[2][2]
-                except IndexError:
-                    template_debug_result = normal_string_result
-
-            else:
-                normal_string_result = vals[2]
-                invalid_string_result = vals[2]
-                template_debug_result = vals[2]
-
-            with translation.override(vals[1].get('LANGUAGE_CODE', 'en-us')):
-
-                for invalid_str, template_debug, result in [
-                        ('', False, normal_string_result),
-                        (expected_invalid_str, False, invalid_string_result),
-                        ('', True, template_debug_result)
-                ]:
-                    with override_settings(TEMPLATE_STRING_IF_INVALID=invalid_str,
-                                           TEMPLATE_DEBUG=template_debug):
-                        for is_cached in (False, True):
-                            try:
-                                try:
-                                    with warnings.catch_warnings():
-                                        # Ignore pending deprecations of loading 'ssi' and 'url' tags from future.
-                                        warnings.filterwarnings("ignore", category=RemovedInDjango19Warning, module='django.templatetags.future')
-                                        # Ignore deprecations of loading 'cycle' and 'firstof' tags from future.
-                                        warnings.filterwarnings("ignore", category=RemovedInDjango20Warning, module="django.templatetags.future")
-                                        test_template = loader.get_template(name)
-                                except ShouldNotExecuteException:
-                                    failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Template loading invoked method that shouldn't have been invoked." % (is_cached, invalid_str, template_debug, name))
+            # Set TEMPLATE_STRING_IF_INVALID to a known string.
+            expected_invalid_str = 'INVALID'
+
+            # Warm the URL reversing cache. This ensures we don't pay the cost
+            # warming the cache during one of the tests.
+            urlresolvers.reverse('template_tests.views.client_action',
+                                 kwargs={'id': 0, 'action': "update"})
+
+            for name, vals in tests:
+                if isinstance(vals[2], tuple):
+                    normal_string_result = vals[2][0]
+                    invalid_string_result = vals[2][1]
 
+                    if isinstance(invalid_string_result, tuple):
+                        expected_invalid_str = 'INVALID %s'
+                        invalid_string_result = invalid_string_result[0] % invalid_string_result[1]
+                        template_base.invalid_var_format_string = True
+
+                    try:
+                        template_debug_result = vals[2][2]
+                    except IndexError:
+                        template_debug_result = normal_string_result
+
+                else:
+                    normal_string_result = vals[2]
+                    invalid_string_result = vals[2]
+                    template_debug_result = vals[2]
+
+                with translation.override(vals[1].get('LANGUAGE_CODE', 'en-us')):
+                    for invalid_str, template_debug, result in [
+                            ('', False, normal_string_result),
+                            (expected_invalid_str, False, invalid_string_result),
+                            ('', True, template_debug_result)
+                    ]:
+                        with override_settings(TEMPLATE_STRING_IF_INVALID=invalid_str,
+                                               TEMPLATE_DEBUG=template_debug):
+                            for is_cached in (False, True):
                                 try:
-                                    with warnings.catch_warnings():
-                                        # Ignore deprecations of using the wrong number of variables with the 'for' tag.
-                                        warnings.filterwarnings("ignore", category=RemovedInDjango20Warning, module="django.template.defaulttags")
-                                        output = self.render(test_template, vals)
-                                except ShouldNotExecuteException:
-                                    failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Template rendering invoked method that shouldn't have been invoked." % (is_cached, invalid_str, template_debug, name))
-                            except ContextStackException:
-                                failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Context stack was left imbalanced" % (is_cached, invalid_str, template_debug, name))
-                                continue
-                            except Exception:
-                                exc_type, exc_value, exc_tb = sys.exc_info()
-                                if exc_type != result:
-                                    tb = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_tb))
-                                    failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Got %s, exception: %s\n%s" % (is_cached, invalid_str, template_debug, name, exc_type, exc_value, tb))
-                                continue
-                            if output != result:
-                                failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Expected %r, got %r" % (is_cached, invalid_str, template_debug, name, result, output))
-                        cache_loader.reset()
+                                    try:
+                                        with warnings.catch_warnings():
+                                            # Ignore pending deprecations of loading 'ssi' and 'url' tags from future.
+                                            warnings.filterwarnings("ignore", category=RemovedInDjango19Warning, module='django.templatetags.future')
+                                            # Ignore deprecations of loading 'cycle' and 'firstof' tags from future.
+                                            warnings.filterwarnings("ignore", category=RemovedInDjango20Warning, module="django.templatetags.future")
+                                            test_template = loader.get_template(name)
+                                    except ShouldNotExecuteException:
+                                        failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Template loading invoked method that shouldn't have been invoked." % (is_cached, invalid_str, template_debug, name))
+
+                                    try:
+                                        with warnings.catch_warnings():
+                                            # Ignore deprecations of using the wrong number of variables with the 'for' tag.
+                                            warnings.filterwarnings("ignore", category=RemovedInDjango20Warning, module="django.template.defaulttags")
+                                            output = self.render(test_template, vals)
+                                    except ShouldNotExecuteException:
+                                        failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Template rendering invoked method that shouldn't have been invoked." % (is_cached, invalid_str, template_debug, name))
+                                except ContextStackException:
+                                    failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Context stack was left imbalanced" % (is_cached, invalid_str, template_debug, name))
+                                    continue
+                                except Exception:
+                                    exc_type, exc_value, exc_tb = sys.exc_info()
+                                    if exc_type != result:
+                                        tb = '\n'.join(traceback.format_exception(exc_type, exc_value, exc_tb))
+                                        failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Got %s, exception: %s\n%s" % (is_cached, invalid_str, template_debug, name, exc_type, exc_value, tb))
+                                    continue
+                                if output != result:
+                                    failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s', TEMPLATE_DEBUG=%s): %s -- FAILED. Expected %r, got %r" % (is_cached, invalid_str, template_debug, name, result, output))
+                    cache_loader.reset()
 
                 if template_base.invalid_var_format_string:
                     expected_invalid_str = 'INVALID'
                     template_base.invalid_var_format_string = False
 
-        restore_template_loaders()
-
         self.assertEqual(failures, [], "Tests failed:\n%s\n%s" %
             ('-' * 70, ("\n%s\n" % ('-' * 70)).join(failures)))
 
@@ -1887,13 +1856,13 @@ class RequestContextTests(unittest.TestCase):
 
     def setUp(self):
         templates = {
-            'child': Template('{{ var|default:"none" }}'),
+            'child': '{{ var|default:"none" }}',
         }
-        setup_test_template_loader(templates)
+        override_with_test_loader.override(templates)
         self.fake_request = RequestFactory().get('/')
 
     def tearDown(self):
-        restore_template_loaders()
+        override_with_test_loader.restore()
 
     def test_include_only(self):
         """

+ 4 - 12
tests/view_tests/tests/test_debug.py

@@ -17,8 +17,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile
 from django.core.urlresolvers import reverse
 from django.template.base import TemplateDoesNotExist
 from django.test import TestCase, RequestFactory, override_settings
-from django.test.utils import (
-    setup_test_template_loader, restore_template_loaders)
+from django.test.utils import override_with_test_loader
 from django.utils.encoding import force_text, force_bytes
 from django.utils import six
 from django.views.debug import ExceptionReporter
@@ -47,23 +46,16 @@ class DebugViewTests(TestCase):
 
     def test_403(self):
         # Ensure no 403.html template exists to test the default case.
-        setup_test_template_loader({})
-        try:
+        with override_with_test_loader({}):
             response = self.client.get('/raises403/')
             self.assertContains(response, '<h1>403 Forbidden</h1>', status_code=403)
-        finally:
-            restore_template_loaders()
 
     def test_403_template(self):
         # Set up a test 403.html template.
-        setup_test_template_loader(
-            {'403.html': 'This is a test template for a 403 Forbidden error.'}
-        )
-        try:
+        with override_with_test_loader({'403.html': 'This is a test template '
+                                        'for a 403 Forbidden error.'}):
             response = self.client.get('/raises403/')
             self.assertContains(response, 'test template', status_code=403)
-        finally:
-            restore_template_loaders()
 
     def test_404(self):
         response = self.client.get('/raises404/')

+ 4 - 9
tests/view_tests/tests/test_defaults.py

@@ -1,8 +1,7 @@
 from __future__ import unicode_literals
 
 from django.test import TestCase
-from django.test.utils import (setup_test_template_loader,
-    restore_template_loaders, override_settings)
+from django.test.utils import override_settings, override_with_test_loader
 
 from ..models import UrlArticle
 
@@ -41,17 +40,13 @@ class DefaultsTests(TestCase):
         Test that 404.html and 500.html templates are picked by their respective
         handler.
         """
-        setup_test_template_loader(
-            {'404.html': 'This is a test template for a 404 error.',
-             '500.html': 'This is a test template for a 500 error.'}
-        )
-        try:
+        with override_with_test_loader({
+                '404.html': 'This is a test template for a 404 error.',
+                '500.html': 'This is a test template for a 500 error.'}):
             for code, url in ((404, '/non_existing_url/'), (500, '/server_error/')):
                 response = self.client.get(url)
                 self.assertContains(response, "test template for a %d error" % code,
                     status_code=code)
-        finally:
-            restore_template_loaders()
 
     def test_get_absolute_url_attributes(self):
         "A model can set attributes on the get_absolute_url method"