From 806efe912b846c1fde250c9321d8334b7517cd56 Mon Sep 17 00:00:00 2001 From: Ad Timmering Date: Sat, 1 Jan 2022 14:55:55 +0900 Subject: [PATCH] Fixed #33400 -- Added support for msg_prefix and count arguments to assertTemplateUsed()/assertTemplateNotUsed() used as context managers. --- django/test/testcases.py | 62 +++++++++++++++++++-------------------- tests/test_utils/tests.py | 48 ++++++++++++++++++++++++++---- 2 files changed, 73 insertions(+), 37 deletions(-) diff --git a/django/test/testcases.py b/django/test/testcases.py index 367076d1a98..685cbe2bd4f 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -93,9 +93,12 @@ class _AssertNumQueriesContext(CaptureQueriesContext): class _AssertTemplateUsedContext: - def __init__(self, test_case, template_name): + def __init__(self, test_case, template_name, msg_prefix='', count=None): self.test_case = test_case self.template_name = template_name + self.msg_prefix = msg_prefix + self.count = count + self.rendered_templates = [] self.rendered_template_names = [] self.context = ContextList() @@ -106,10 +109,10 @@ class _AssertTemplateUsedContext: self.context.append(copy(context)) def test(self): - return self.template_name in self.rendered_template_names - - def message(self): - return '%s was not rendered.' % self.template_name + self.test_case._assert_template_used( + self.template_name, self.rendered_template_names, self.msg_prefix, + self.count, + ) def __enter__(self): template_rendered.connect(self.on_template_render) @@ -119,24 +122,16 @@ class _AssertTemplateUsedContext: template_rendered.disconnect(self.on_template_render) if exc_type is not None: return - - if not self.test(): - message = self.message() - if self.rendered_templates: - message += ' Following templates were rendered: %s' % ( - ', '.join(self.rendered_template_names) - ) - else: - message += ' No template was rendered.' - self.test_case.fail(message) + self.test() class _AssertTemplateNotUsedContext(_AssertTemplateUsedContext): def test(self): - return self.template_name not in self.rendered_template_names - - def message(self): - return '%s was rendered.' % self.template_name + self.test_case.assertFalse( + self.template_name in self.rendered_template_names, + f"{self.msg_prefix}Template '{self.template_name}' was used " + f"unexpectedly in rendering the response" + ) class DatabaseOperationForbidden(AssertionError): @@ -646,18 +641,7 @@ class SimpleTestCase(unittest.TestCase): template_names = [t.name for t in response.templates if t.name is not None] return None, template_names, msg_prefix - def assertTemplateUsed(self, response=None, template_name=None, msg_prefix='', count=None): - """ - Assert that the template with the provided name was used in rendering - the response. Also usable as context manager. - """ - context_mgr_template, template_names, msg_prefix = self._get_template_used( - response, template_name, msg_prefix, 'assertTemplateUsed', - ) - if context_mgr_template: - # Use assertTemplateUsed as context manager. - return _AssertTemplateUsedContext(self, context_mgr_template) - + def _assert_template_used(self, template_name, template_names, msg_prefix, count): if not template_names: self.fail(msg_prefix + "No templates used to render the response") self.assertTrue( @@ -675,6 +659,20 @@ class SimpleTestCase(unittest.TestCase): % (template_name, count, template_names.count(template_name)) ) + def assertTemplateUsed(self, response=None, template_name=None, msg_prefix='', count=None): + """ + Assert that the template with the provided name was used in rendering + the response. Also usable as context manager. + """ + context_mgr_template, template_names, msg_prefix = self._get_template_used( + response, template_name, msg_prefix, 'assertTemplateUsed', + ) + if context_mgr_template: + # Use assertTemplateUsed as context manager. + return _AssertTemplateUsedContext(self, context_mgr_template, msg_prefix, count) + + self._assert_template_used(template_name, template_names, msg_prefix, count) + def assertTemplateNotUsed(self, response=None, template_name=None, msg_prefix=''): """ Assert that the template with the provided name was NOT used in @@ -685,7 +683,7 @@ class SimpleTestCase(unittest.TestCase): ) if context_mgr_template: # Use assertTemplateNotUsed as context manager. - return _AssertTemplateNotUsedContext(self, context_mgr_template) + return _AssertTemplateNotUsedContext(self, context_mgr_template, msg_prefix) self.assertFalse( template_name in template_names, diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py index a2cb12c20e9..2addc1fdde6 100644 --- a/tests/test_utils/tests.py +++ b/tests/test_utils/tests.py @@ -508,7 +508,7 @@ class AssertTemplateUsedContextManagerTests(SimpleTestCase): pass def test_error_message(self): - msg = 'template_used/base.html was not rendered. No template was rendered.' + msg = 'No templates used to render the response' with self.assertRaisesMessage(AssertionError, msg): with self.assertTemplateUsed('template_used/base.html'): pass @@ -518,8 +518,8 @@ class AssertTemplateUsedContextManagerTests(SimpleTestCase): pass msg2 = ( - 'template_used/base.html was not rendered. Following templates ' - 'were rendered: template_used/alternative.html' + "Template 'template_used/base.html' was not a template used to render " + "the response. Actual template(s) used: template_used/alternative.html" ) with self.assertRaisesMessage(AssertionError, msg2): with self.assertTemplateUsed('template_used/base.html'): @@ -529,6 +529,43 @@ class AssertTemplateUsedContextManagerTests(SimpleTestCase): response = self.client.get('/test_utils/no_template_used/') self.assertTemplateUsed(response, 'template_used/base.html') + def test_msg_prefix(self): + msg_prefix = 'Prefix' + msg = f'{msg_prefix}: No templates used to render the response' + with self.assertRaisesMessage(AssertionError, msg): + with self.assertTemplateUsed('template_used/base.html', msg_prefix=msg_prefix): + pass + + with self.assertRaisesMessage(AssertionError, msg): + with self.assertTemplateUsed( + template_name='template_used/base.html', + msg_prefix=msg_prefix, + ): + pass + + msg = ( + f"{msg_prefix}: Template 'template_used/base.html' was not a " + f"template used to render the response. Actual template(s) used: " + f"template_used/alternative.html" + ) + with self.assertRaisesMessage(AssertionError, msg): + with self.assertTemplateUsed('template_used/base.html', msg_prefix=msg_prefix): + render_to_string('template_used/alternative.html') + + def test_count(self): + with self.assertTemplateUsed('template_used/base.html', count=2): + render_to_string('template_used/base.html') + render_to_string('template_used/base.html') + + msg = ( + "Template 'template_used/base.html' was expected to be rendered " + "3 time(s) but was actually rendered 2 time(s)." + ) + with self.assertRaisesMessage(AssertionError, msg): + with self.assertTemplateUsed('template_used/base.html', count=3): + render_to_string('template_used/base.html') + render_to_string('template_used/base.html') + def test_failure(self): msg = 'response and/or template_name argument must be provided' with self.assertRaisesMessage(TypeError, msg): @@ -549,8 +586,9 @@ class AssertTemplateUsedContextManagerTests(SimpleTestCase): pass msg = ( - 'template_used/base.html was not rendered. Following ' - 'templates were rendered: template_used/alternative.html' + "Template 'template_used/base.html' was not a template used to " + "render the response. Actual template(s) used: " + "template_used/alternative.html" ) with self.assertRaisesMessage(AssertionError, msg): with self.assertTemplateUsed('template_used/base.html'):