Commit a678e9ea authored by Carl Meyer's avatar Carl Meyer
Browse files

Fixed #17604 - Added context-manager capability to assertTemplateUsed and...

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
parent f1dc83cb
Loading
Loading
Loading
Loading
+75 −5
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ from __future__ import with_statement
import os
import re
import sys
from copy import copy
from functools import wraps
from urlparse import urlsplit, urlunsplit
from xml.dom.minidom import parseString, Node
@@ -28,8 +29,10 @@ from django.forms.fields import CharField
from django.http import QueryDict
from django.test import _doctest as doctest
from django.test.client import Client
from django.test.signals import template_rendered
from django.test.utils import (get_warnings_state, restore_warnings_state,
    override_settings)
from django.test.utils import ContextList
from django.utils import simplejson, unittest as ut2
from django.utils.encoding import smart_str, force_unicode
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):
        """
        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"
                      " 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
        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:
            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]
        if not template_names:
            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" %
                (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
        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:
            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]
        self.assertFalse(template_name in template_names,
            msg_prefix + "Template '%s' was used unexpectedly in rendering"
+15 −0
Original line number Diff line number Diff line
@@ -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,
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+19 −0
Original line number Diff line number Diff line
@@ -1575,11 +1575,30 @@ your test suite.

    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='')

    Asserts that the template with the given name was *not* used in rendering
    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='')

    Asserts that the response return a ``status_code`` redirect status, it
+0 −0

Empty file added.

+0 −0

Empty file added.

Loading