Fixed #22369 -- Added count parameter to assertTemplateUsed

This commit is contained in:
Jacob R. Rothenbuhler 2014-04-14 15:13:49 -04:00 committed by Simon Charette
parent 09af48c70f
commit 17c1884456
6 changed files with 59 additions and 3 deletions

View File

@ -521,7 +521,7 @@ class SimpleTestCase(unittest.TestCase):
None] None]
return None, template_names, msg_prefix return None, template_names, msg_prefix
def assertTemplateUsed(self, response=None, template_name=None, msg_prefix=''): def assertTemplateUsed(self, response=None, template_name=None, msg_prefix='', count=None):
""" """
Asserts that the template with the provided name was used in rendering Asserts that the template with the provided name was used in rendering
the response. Also usable as context manager. the response. Also usable as context manager.
@ -540,6 +540,12 @@ class SimpleTestCase(unittest.TestCase):
" the response. Actual template(s) used: %s" % " the response. Actual template(s) used: %s" %
(template_name, ', '.join(template_names))) (template_name, ', '.join(template_names)))
if count is not None:
self.assertEqual(template_names.count(template_name), count,
msg_prefix + "Template '%s' was expected to be rendered %d "
"time(s) but was actually rendered %d time(s)." %
(template_name, count, template_names.count(template_name)))
def assertTemplateNotUsed(self, response=None, template_name=None, msg_prefix=''): def assertTemplateNotUsed(self, response=None, template_name=None, msg_prefix=''):
""" """
Asserts that the template with the provided name was NOT used in Asserts that the template with the provided name was NOT used in

View File

@ -154,7 +154,9 @@ Requests and Responses
Tests Tests
^^^^^ ^^^^^
* ... * The ``count`` argument was added to
:meth:`~django.test.SimpleTestCase.assertTemplateUsed`. This allows you to
assert that a template was rendered a specific number of times.
Validators Validators
^^^^^^^^^^ ^^^^^^^^^^

View File

@ -1328,13 +1328,19 @@ your test suite.
attribute ordering is not significant. See attribute ordering is not significant. See
:meth:`~SimpleTestCase.assertHTMLEqual` for more details. :meth:`~SimpleTestCase.assertHTMLEqual` for more details.
.. method:: SimpleTestCase.assertTemplateUsed(response, template_name, msg_prefix='') .. method:: SimpleTestCase.assertTemplateUsed(response, template_name, msg_prefix='', count=None)
Asserts that the template with the given name was used in rendering the Asserts that the template with the given name was used in rendering the
response. response.
The name is a string such as ``'admin/index.html'``. The name is a string such as ``'admin/index.html'``.
.. versionadded:: 1.8
The count argument is an integer indicating the number of times the
template should be rendered. Default is ``None``, meaning that the
template should be rendered one or more times.
You can use this as a context manager, like this:: You can use this as a context manager, like this::
with self.assertTemplateUsed('index.html'): with self.assertTemplateUsed('index.html'):

View File

@ -213,6 +213,12 @@ class AssertTemplateUsedTests(TestCase):
except AssertionError as e: except AssertionError as e:
self.assertIn("abc: No templates used to render the response", str(e)) self.assertIn("abc: No templates used to render the response", str(e))
with self.assertRaises(AssertionError) as context:
self.assertTemplateUsed(response, 'GET Template', count=2)
self.assertIn(
"No templates used to render the response",
str(context.exception))
def test_single_context(self): def test_single_context(self):
"Template assertions work when there is a single context" "Template assertions work when there is a single context"
response = self.client.get('/post_view/', {}) response = self.client.get('/post_view/', {})
@ -237,6 +243,21 @@ class AssertTemplateUsedTests(TestCase):
except AssertionError as e: except AssertionError as e:
self.assertIn("abc: Template 'Empty POST Template' was not a template used to render the response. Actual template(s) used: Empty GET Template", str(e)) self.assertIn("abc: Template 'Empty POST Template' was not a template used to render the response. Actual template(s) used: Empty GET Template", str(e))
with self.assertRaises(AssertionError) as context:
self.assertTemplateUsed(response, 'Empty GET Template', count=2)
self.assertIn(
"Template 'Empty GET Template' was expected to be rendered 2 "
"time(s) but was actually rendered 1 time(s).",
str(context.exception))
with self.assertRaises(AssertionError) as context:
self.assertTemplateUsed(
response, 'Empty GET Template', msg_prefix='abc', count=2)
self.assertIn(
"abc: Template 'Empty GET Template' was expected to be rendered 2 "
"time(s) but was actually rendered 1 time(s).",
str(context.exception))
def test_multiple_context(self): def test_multiple_context(self):
"Template assertions work when there are multiple contexts" "Template assertions work when there are multiple contexts"
post_data = { post_data = {
@ -263,6 +284,19 @@ class AssertTemplateUsedTests(TestCase):
except AssertionError as e: except AssertionError as e:
self.assertIn("Template 'Valid POST Template' was not a template used to render the response. Actual template(s) used: form_view.html, base.html", str(e)) self.assertIn("Template 'Valid POST Template' was not a template used to render the response. Actual template(s) used: form_view.html, base.html", str(e))
with self.assertRaises(AssertionError) as context:
self.assertTemplateUsed(response, 'base.html', count=2)
self.assertIn(
"Template 'base.html' was expected to be rendered 2 "
"time(s) but was actually rendered 1 time(s).",
str(context.exception))
def test_template_rendered_multiple_times(self):
"""Template assertions work when a template is rendered multiple times."""
response = self.client.get('/render_template_multiple_times/')
self.assertTemplateUsed(response, 'base.html', count=2)
@override_settings(ROOT_URLCONF='test_client_regress.urls') @override_settings(ROOT_URLCONF='test_client_regress.urls')
class AssertRedirectsTests(TestCase): class AssertRedirectsTests(TestCase):

View File

@ -37,4 +37,5 @@ urlpatterns = [
url(r'^read_all/$', views.read_all), url(r'^read_all/$', views.read_all),
url(r'^read_buffer/$', views.read_buffer), url(r'^read_buffer/$', views.read_buffer),
url(r'^request_context_view/$', views.request_context_view), url(r'^request_context_view/$', views.request_context_view),
url(r'^render_template_multiple_times/$', views.render_template_multiple_times),
] ]

View File

@ -7,6 +7,7 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from django.template import RequestContext from django.template import RequestContext
from django.template.loader import render_to_string
from django.test import Client from django.test import Client
from django.test.client import CONTENT_TYPE_RE from django.test.client import CONTENT_TYPE_RE
from django.test.utils import setup_test_environment from django.test.utils import setup_test_environment
@ -151,3 +152,9 @@ def request_context_view(request):
# Special attribute that won't be present on a plain HttpRequest # Special attribute that won't be present on a plain HttpRequest
request.special_path = request.path request.special_path = request.path
return render_to_response('request_context.html', context_instance=RequestContext(request, {})) return render_to_response('request_context.html', context_instance=RequestContext(request, {}))
def render_template_multiple_times(request):
"""A view that renders a template multiple times."""
return HttpResponse(
render_to_string('base.html') + render_to_string('base.html'))