Fixed #17604 - Added context-manager capability to assertTemplateUsed and assertTemplateNotUsed. Thanks Greg Müllegger.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17412 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
f1dc83cb98
commit
a678e9ea65
|
@ -3,6 +3,7 @@ from __future__ import with_statement
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
from copy import copy
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from urlparse import urlsplit, urlunsplit
|
from urlparse import urlsplit, urlunsplit
|
||||||
from xml.dom.minidom import parseString, Node
|
from xml.dom.minidom import parseString, Node
|
||||||
|
@ -28,8 +29,10 @@ from django.forms.fields import CharField
|
||||||
from django.http import QueryDict
|
from django.http import QueryDict
|
||||||
from django.test import _doctest as doctest
|
from django.test import _doctest as doctest
|
||||||
from django.test.client import Client
|
from django.test.client import Client
|
||||||
|
from django.test.signals import template_rendered
|
||||||
from django.test.utils import (get_warnings_state, restore_warnings_state,
|
from django.test.utils import (get_warnings_state, restore_warnings_state,
|
||||||
override_settings)
|
override_settings)
|
||||||
|
from django.test.utils import ContextList
|
||||||
from django.utils import simplejson, unittest as ut2
|
from django.utils import simplejson, unittest as ut2
|
||||||
from django.utils.encoding import smart_str, force_unicode
|
from django.utils.encoding import smart_str, force_unicode
|
||||||
from django.views.static import serve
|
from django.views.static import serve
|
||||||
|
@ -260,8 +263,53 @@ class _AssertNumQueriesContext(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SimpleTestCase(ut2.TestCase):
|
class _AssertTemplateUsedContext(object):
|
||||||
|
def __init__(self, test_case, template_name):
|
||||||
|
self.test_case = test_case
|
||||||
|
self.template_name = template_name
|
||||||
|
self.rendered_templates = []
|
||||||
|
self.rendered_template_names = []
|
||||||
|
self.context = ContextList()
|
||||||
|
|
||||||
|
def on_template_render(self, sender, signal, template, context, **kwargs):
|
||||||
|
self.rendered_templates.append(template)
|
||||||
|
self.rendered_template_names.append(template.name)
|
||||||
|
self.context.append(copy(context))
|
||||||
|
|
||||||
|
def test(self):
|
||||||
|
return self.template_name in self.rendered_template_names
|
||||||
|
|
||||||
|
def message(self):
|
||||||
|
return u'%s was not rendered.' % self.template_name
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
template_rendered.connect(self.on_template_render)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
template_rendered.disconnect(self.on_template_render)
|
||||||
|
if exc_type is not None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.test():
|
||||||
|
message = self.message()
|
||||||
|
if len(self.rendered_templates) == 0:
|
||||||
|
message += u' No template was rendered.'
|
||||||
|
else:
|
||||||
|
message += u' Following templates were rendered: %s' % (
|
||||||
|
', '.join(self.rendered_template_names))
|
||||||
|
self.test_case.fail(message)
|
||||||
|
|
||||||
|
|
||||||
|
class _AssertTemplateNotUsedContext(_AssertTemplateUsedContext):
|
||||||
|
def test(self):
|
||||||
|
return self.template_name not in self.rendered_template_names
|
||||||
|
|
||||||
|
def message(self):
|
||||||
|
return u'%s was rendered.' % self.template_name
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleTestCase(ut2.TestCase):
|
||||||
def save_warnings_state(self):
|
def save_warnings_state(self):
|
||||||
"""
|
"""
|
||||||
Saves the state of the warnings module
|
Saves the state of the warnings module
|
||||||
|
@ -612,14 +660,25 @@ class TransactionTestCase(SimpleTestCase):
|
||||||
self.fail(msg_prefix + "The form '%s' was not used to render the"
|
self.fail(msg_prefix + "The form '%s' was not used to render the"
|
||||||
" response" % form)
|
" response" % form)
|
||||||
|
|
||||||
def assertTemplateUsed(self, response, template_name, msg_prefix=''):
|
def assertTemplateUsed(self, response=None, template_name=None, msg_prefix=''):
|
||||||
"""
|
"""
|
||||||
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.
|
the response. Also useable as context manager.
|
||||||
"""
|
"""
|
||||||
|
if response is None and template_name is None:
|
||||||
|
raise TypeError(u'response and/or template_name argument must be provided')
|
||||||
|
|
||||||
if msg_prefix:
|
if msg_prefix:
|
||||||
msg_prefix += ": "
|
msg_prefix += ": "
|
||||||
|
|
||||||
|
# use assertTemplateUsed as context manager
|
||||||
|
if not hasattr(response, 'templates') or (response is None and template_name):
|
||||||
|
if response:
|
||||||
|
template_name = response
|
||||||
|
response = None
|
||||||
|
context = _AssertTemplateUsedContext(self, template_name)
|
||||||
|
return context
|
||||||
|
|
||||||
template_names = [t.name for t in response.templates]
|
template_names = [t.name for t in response.templates]
|
||||||
if not template_names:
|
if not template_names:
|
||||||
self.fail(msg_prefix + "No templates used to render the response")
|
self.fail(msg_prefix + "No templates used to render the response")
|
||||||
|
@ -628,14 +687,25 @@ class TransactionTestCase(SimpleTestCase):
|
||||||
" the response. Actual template(s) used: %s" %
|
" the response. Actual template(s) used: %s" %
|
||||||
(template_name, u', '.join(template_names)))
|
(template_name, u', '.join(template_names)))
|
||||||
|
|
||||||
def assertTemplateNotUsed(self, response, template_name, 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
|
||||||
rendering the response.
|
rendering the response. Also useable as context manager.
|
||||||
"""
|
"""
|
||||||
|
if response is None and template_name is None:
|
||||||
|
raise TypeError(u'response and/or template_name argument must be provided')
|
||||||
|
|
||||||
if msg_prefix:
|
if msg_prefix:
|
||||||
msg_prefix += ": "
|
msg_prefix += ": "
|
||||||
|
|
||||||
|
# use assertTemplateUsed as context manager
|
||||||
|
if not hasattr(response, 'templates') or (response is None and template_name):
|
||||||
|
if response:
|
||||||
|
template_name = response
|
||||||
|
response = None
|
||||||
|
context = _AssertTemplateNotUsedContext(self, template_name)
|
||||||
|
return context
|
||||||
|
|
||||||
template_names = [t.name for t in response.templates]
|
template_names = [t.name for t in response.templates]
|
||||||
self.assertFalse(template_name in template_names,
|
self.assertFalse(template_name in template_names,
|
||||||
msg_prefix + "Template '%s' was used unexpectedly in rendering"
|
msg_prefix + "Template '%s' was used unexpectedly in rendering"
|
||||||
|
|
|
@ -946,6 +946,21 @@ apply URL escaping again. This is wrong for URLs whose unquoted form contains
|
||||||
a ``%xx`` sequence, but such URLs are very unlikely to happen in the wild,
|
a ``%xx`` sequence, but such URLs are very unlikely to happen in the wild,
|
||||||
since they would confuse browsers too.
|
since they would confuse browsers too.
|
||||||
|
|
||||||
|
``assertTemplateUsed`` and ``assertTemplateNotUsed`` as context manager
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
It is now possible to check whether a template was used or not in a block of
|
||||||
|
code with the :meth:`~django.test.testcase.TestCase.assertTemplateUsed` and
|
||||||
|
:meth:`~django.test.testcase.TestCase.assertTemplateNotUsed` assertions. They
|
||||||
|
can be used as a context manager::
|
||||||
|
|
||||||
|
with self.assertTemplateUsed('index.html'):
|
||||||
|
render_to_string('index.html')
|
||||||
|
with self.assertTemplateNotUsed('base.html'):
|
||||||
|
render_to_string('index.html')
|
||||||
|
|
||||||
|
See the :ref:`assertion documentation<assertions>` for more information.
|
||||||
|
|
||||||
Database connections after running the test suite
|
Database connections after running the test suite
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1575,11 +1575,30 @@ your test suite.
|
||||||
|
|
||||||
The name is a string such as ``'admin/index.html'``.
|
The name is a string such as ``'admin/index.html'``.
|
||||||
|
|
||||||
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
|
You can also use this as a context manager. The code that is executed
|
||||||
|
under the with statement is then observed instead of a response::
|
||||||
|
|
||||||
|
# This is necessary in Python 2.5 to enable the with statement, in 2.6
|
||||||
|
# and up it is no longer necessary.
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
|
with self.assertTemplateUsed('index.html'):
|
||||||
|
render_to_string('index.html')
|
||||||
|
with self.assertTemplateUsed(template_name='index.html'):
|
||||||
|
render_to_string('index.html')
|
||||||
|
|
||||||
.. method:: TestCase.assertTemplateNotUsed(response, template_name, msg_prefix='')
|
.. method:: TestCase.assertTemplateNotUsed(response, template_name, msg_prefix='')
|
||||||
|
|
||||||
Asserts that the template with the given name was *not* used in rendering
|
Asserts that the template with the given name was *not* used in rendering
|
||||||
the response.
|
the response.
|
||||||
|
|
||||||
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
|
You can use this as a context manager in the same way as
|
||||||
|
:func:`~TestCase.assertTemplateUsed`.
|
||||||
|
|
||||||
.. method:: TestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='')
|
.. method:: TestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='')
|
||||||
|
|
||||||
Asserts that the response return a ``status_code`` redirect status, it
|
Asserts that the response return a ``status_code`` redirect status, it
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{% extends "template_used/base.html" %}
|
|
@ -0,0 +1 @@
|
||||||
|
{% include "template_used/base.html" %}
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import with_statement, absolute_import
|
from __future__ import with_statement, absolute_import
|
||||||
|
|
||||||
from django.forms import EmailField, IntegerField
|
from django.forms import EmailField, IntegerField
|
||||||
|
from django.template.loader import render_to_string
|
||||||
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
|
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
|
||||||
from django.utils.unittest import skip
|
from django.utils.unittest import skip
|
||||||
|
|
||||||
|
@ -88,6 +89,92 @@ class AssertNumQueriesContextManagerTests(TestCase):
|
||||||
self.client.get("/test_utils/get_person/%s/" % person.pk)
|
self.client.get("/test_utils/get_person/%s/" % person.pk)
|
||||||
|
|
||||||
|
|
||||||
|
class AssertTemplateUsedContextManagerTests(TestCase):
|
||||||
|
def test_usage(self):
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
render_to_string('template_used/base.html')
|
||||||
|
|
||||||
|
with self.assertTemplateUsed(template_name='template_used/base.html'):
|
||||||
|
render_to_string('template_used/base.html')
|
||||||
|
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
render_to_string('template_used/include.html')
|
||||||
|
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
render_to_string('template_used/extends.html')
|
||||||
|
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
render_to_string('template_used/base.html')
|
||||||
|
render_to_string('template_used/base.html')
|
||||||
|
|
||||||
|
def test_nested_usage(self):
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
with self.assertTemplateUsed('template_used/include.html'):
|
||||||
|
render_to_string('template_used/include.html')
|
||||||
|
|
||||||
|
with self.assertTemplateUsed('template_used/extends.html'):
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
render_to_string('template_used/extends.html')
|
||||||
|
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
with self.assertTemplateUsed('template_used/alternative.html'):
|
||||||
|
render_to_string('template_used/alternative.html')
|
||||||
|
render_to_string('template_used/base.html')
|
||||||
|
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
render_to_string('template_used/extends.html')
|
||||||
|
with self.assertTemplateNotUsed('template_used/base.html'):
|
||||||
|
render_to_string('template_used/alternative.html')
|
||||||
|
render_to_string('template_used/base.html')
|
||||||
|
|
||||||
|
def test_not_used(self):
|
||||||
|
with self.assertTemplateNotUsed('template_used/base.html'):
|
||||||
|
pass
|
||||||
|
with self.assertTemplateNotUsed('template_used/alternative.html'):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_error_message(self):
|
||||||
|
try:
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
pass
|
||||||
|
except AssertionError, e:
|
||||||
|
self.assertTrue('template_used/base.html' in e.message)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with self.assertTemplateUsed(template_name='template_used/base.html'):
|
||||||
|
pass
|
||||||
|
except AssertionError, e:
|
||||||
|
self.assertTrue('template_used/base.html' in e.message)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
render_to_string('template_used/alternative.html')
|
||||||
|
except AssertionError, e:
|
||||||
|
self.assertTrue('template_used/base.html' in e.message, e.message)
|
||||||
|
self.assertTrue('template_used/alternative.html' in e.message, e.message)
|
||||||
|
|
||||||
|
def test_failure(self):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
with self.assertTemplateUsed():
|
||||||
|
pass
|
||||||
|
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
with self.assertTemplateUsed(''):
|
||||||
|
pass
|
||||||
|
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
with self.assertTemplateUsed(''):
|
||||||
|
render_to_string('template_used/base.html')
|
||||||
|
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
with self.assertTemplateUsed(template_name=''):
|
||||||
|
pass
|
||||||
|
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
with self.assertTemplateUsed('template_used/base.html'):
|
||||||
|
render_to_string('template_used/alternative.html')
|
||||||
|
|
||||||
|
|
||||||
class SaveRestoreWarningState(TestCase):
|
class SaveRestoreWarningState(TestCase):
|
||||||
def test_save_restore_warnings_state(self):
|
def test_save_restore_warnings_state(self):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue