Ticket #17604: 17604-assertTemplateUsed.1.diff

File 17604-assertTemplateUsed.1.diff, 12.9 KB (added by Gregor Müllegger, 13 years ago)
  • django/test/testcases.py

    diff --git a/django/test/testcases.py b/django/test/testcases.py
    index 53ea02a..2e011e4 100644
    a b from __future__ import with_statement  
    33import os
    44import re
    55import sys
     6from copy import copy
    67from functools import wraps
    78from urlparse import urlsplit, urlunsplit
    89from xml.dom.minidom import parseString, Node
    from django.forms.fields import CharField  
    2829from django.http import QueryDict
    2930from django.test import _doctest as doctest
    3031from django.test.client import Client
     32from django.test.signals import template_rendered
    3133from django.test.utils import (get_warnings_state, restore_warnings_state,
    3234    override_settings)
     35from django.test.utils import ContextList
    3336from django.utils import simplejson, unittest as ut2
    3437from django.utils.encoding import smart_str, force_unicode
    3538from django.views.static import serve
    class _AssertNumQueriesContext(object):  
    260263        )
    261264
    262265
    263 class SimpleTestCase(ut2.TestCase):
     266class _AssertTemplateUsedContext(object):
     267    def __init__(self, test_case, template_name):
     268        self.test_case = test_case
     269        self.template_name = template_name
     270        self.rendered_templates = []
     271        self.rendered_template_names = []
     272        self.context = ContextList()
     273
     274    def on_template_render(self, sender, signal, template, context, **kwargs):
     275        self.rendered_templates.append(template)
     276        self.rendered_template_names.append(template.name)
     277        self.context.append(copy(context))
     278
     279    def test(self):
     280        return self.template_name in self.rendered_template_names
     281
     282    def message(self):
     283        return u'%s was not rendered.' % self.template_name
     284
     285    def __enter__(self):
     286        template_rendered.connect(self.on_template_render)
     287        return self
     288
     289    def __exit__(self, exc_type, exc_value, traceback):
     290        template_rendered.disconnect(self.on_template_render)
     291        if exc_type is not None:
     292            return
    264293
     294        if not self.test():
     295            message = self.message()
     296            if len(self.rendered_templates) == 0:
     297                message += u' No template was rendered.'
     298            else:
     299                message += u' Following templates were rendered: %s' % (
     300                    ', '.join(self.rendered_template_names))
     301            self.test_case.fail(message)
     302
     303
     304class _AssertTemplateNotUsedContext(_AssertTemplateUsedContext):
     305    def test(self):
     306        return self.template_name not in self.rendered_template_names
     307
     308    def message(self):
     309        return u'%s was rendered.' % self.template_name
     310
     311
     312class SimpleTestCase(ut2.TestCase):
    265313    def save_warnings_state(self):
    266314        """
    267315        Saves the state of the warnings module
    class TransactionTestCase(SimpleTestCase):  
    612660            self.fail(msg_prefix + "The form '%s' was not used to render the"
    613661                      " response" % form)
    614662
    615     def assertTemplateUsed(self, response, template_name, msg_prefix=''):
     663    def assertTemplateUsed(self, response=None, template_name=None, msg_prefix=''):
    616664        """
    617665        Asserts that the template with the provided name was used in rendering
    618         the response.
     666        the response. Also useable as context manager.
    619667        """
     668        if response is None and template_name is None:
     669            raise TypeError(u'response and/or template_name argument must be provided')
     670
    620671        if msg_prefix:
    621672            msg_prefix += ": "
    622673
     674        # use assertTemplateUsed as context manager
     675        if not hasattr(response, 'templates') or (response is None and template_name):
     676            if response:
     677                template_name = response
     678                response = None
     679            context = _AssertTemplateUsedContext(self, template_name)
     680            return context
     681
    623682        template_names = [t.name for t in response.templates]
    624683        if not template_names:
    625684            self.fail(msg_prefix + "No templates used to render the response")
    class TransactionTestCase(SimpleTestCase):  
    628687            " the response. Actual template(s) used: %s" %
    629688                (template_name, u', '.join(template_names)))
    630689
    631     def assertTemplateNotUsed(self, response, template_name, msg_prefix=''):
     690    def assertTemplateNotUsed(self, response=None, template_name=None, msg_prefix=''):
    632691        """
    633692        Asserts that the template with the provided name was NOT used in
    634         rendering the response.
     693        rendering the response. Also useable as context manager.
    635694        """
     695        if response is None and template_name is None:
     696            raise TypeError(u'response and/or template_name argument must be provided')
     697
    636698        if msg_prefix:
    637699            msg_prefix += ": "
    638700
     701        # use assertTemplateUsed as context manager
     702        if not hasattr(response, 'templates') or (response is None and template_name):
     703            if response:
     704                template_name = response
     705                response = None
     706            context = _AssertTemplateNotUsedContext(self, template_name)
     707            return context
     708
    639709        template_names = [t.name for t in response.templates]
    640710        self.assertFalse(template_name in template_names,
    641711            msg_prefix + "Template '%s' was used unexpectedly in rendering"
  • docs/releases/1.4.txt

    diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt
    index 9b3c219..2c7cbf1 100644
    a b apply URL escaping again. This is wrong for URLs whose unquoted form contains  
    942942a ``%xx`` sequence, but such URLs are very unlikely to happen in the wild,
    943943since they would confuse browsers too.
    944944
     945``assertTemplateUsed`` and ``assertTemplateNotUsed`` as context manager
     946~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     947
     948It is now possible to check whether a template was used or not in a block of
     949code with the :meth:`~django.test.testcase.TestCase.assertTemplateUsed` and
     950:meth:`~django.test.testcase.TestCase.assertTemplateNotUsed` assertions. They
     951can be used as a context manager::
     952
     953    with self.assertTemplateUsed('index.html'):
     954        render_to_string('index.html')
     955    with self.assertTemplateNotUsed('base.html'):
     956        render_to_string('index.html')
     957
     958See the :ref:`assertion documentation<assertions>` for more information.
     959
    945960Features deprecated in 1.4
    946961==========================
    947962
  • docs/topics/testing.txt

    diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt
    index ea2c52b..f0f0b44 100644
    a b your test suite.  
    15751575
    15761576    The name is a string such as ``'admin/index.html'``.
    15771577
     1578    .. versionadded:: 1.4
     1579
     1580    You can also use this as a context manager. The code that is executed
     1581    under the with statement is then observed instead of a response::
     1582
     1583        # This is necessary in Python 2.5 to enable the with statement, in 2.6
     1584        # and up it is no longer necessary.
     1585        from __future__ import with_statement
     1586
     1587        with self.assertTemplateUsed('index.html'):
     1588            render_to_string('index.html')
     1589        with self.assertTemplateUsed(template_name='index.html'):
     1590            render_to_string('index.html')
     1591
    15781592.. method:: TestCase.assertTemplateNotUsed(response, template_name, msg_prefix='')
    15791593
    15801594    Asserts that the template with the given name was *not* used in rendering
    15811595    the response.
    15821596
     1597    .. versionadded:: 1.4
     1598
     1599    You can use this as a context manager in the same way as
     1600    :func:`~TestCase.assertTemplateUsed`.
     1601
    15831602.. method:: TestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='')
    15841603
    15851604    Asserts that the response return a ``status_code`` redirect status, it
  • new file tests/regressiontests/test_utils/templates/template_used/extends.html

    diff --git a/tests/regressiontests/test_utils/templates/template_used/alternative.html b/tests/regressiontests/test_utils/templates/template_used/alternative.html
    new file mode 100644
    index 0000000..e69de29
    diff --git a/tests/regressiontests/test_utils/templates/template_used/base.html b/tests/regressiontests/test_utils/templates/template_used/base.html
    new file mode 100644
    index 0000000..e69de29
    diff --git a/tests/regressiontests/test_utils/templates/template_used/extends.html b/tests/regressiontests/test_utils/templates/template_used/extends.html
    new file mode 100644
    index 0000000..d14bfa2
    - +  
     1{% extends "template_used/base.html" %}
  • new file tests/regressiontests/test_utils/templates/template_used/include.html

    diff --git a/tests/regressiontests/test_utils/templates/template_used/include.html b/tests/regressiontests/test_utils/templates/template_used/include.html
    new file mode 100644
    index 0000000..2d6c954
    - +  
     1{% include "template_used/base.html" %}
  • tests/regressiontests/test_utils/tests.py

    diff --git a/tests/regressiontests/test_utils/tests.py b/tests/regressiontests/test_utils/tests.py
    index eab6895..b578bff 100644
    a b  
    11from __future__ import with_statement, absolute_import
    22
    33from django.forms import EmailField, IntegerField
     4from django.template.loader import render_to_string
    45from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
    56from django.utils.unittest import skip
    67
    class AssertNumQueriesContextManagerTests(TestCase):  
    8889            self.client.get("/test_utils/get_person/%s/" % person.pk)
    8990
    9091
     92class AssertTemplateUsedContextManagerTests(TestCase):
     93    def test_usage(self):
     94        with self.assertTemplateUsed('template_used/base.html'):
     95            render_to_string('template_used/base.html')
     96
     97        with self.assertTemplateUsed(template_name='template_used/base.html'):
     98            render_to_string('template_used/base.html')
     99
     100        with self.assertTemplateUsed('template_used/base.html'):
     101            render_to_string('template_used/include.html')
     102
     103        with self.assertTemplateUsed('template_used/base.html'):
     104            render_to_string('template_used/extends.html')
     105
     106        with self.assertTemplateUsed('template_used/base.html'):
     107            render_to_string('template_used/base.html')
     108            render_to_string('template_used/base.html')
     109
     110    def test_nested_usage(self):
     111        with self.assertTemplateUsed('template_used/base.html'):
     112            with self.assertTemplateUsed('template_used/include.html'):
     113                render_to_string('template_used/include.html')
     114
     115        with self.assertTemplateUsed('template_used/extends.html'):
     116            with self.assertTemplateUsed('template_used/base.html'):
     117                render_to_string('template_used/extends.html')
     118
     119        with self.assertTemplateUsed('template_used/base.html'):
     120            with self.assertTemplateUsed('template_used/alternative.html'):
     121                render_to_string('template_used/alternative.html')
     122            render_to_string('template_used/base.html')
     123
     124        with self.assertTemplateUsed('template_used/base.html'):
     125            render_to_string('template_used/extends.html')
     126            with self.assertTemplateNotUsed('template_used/base.html'):
     127                render_to_string('template_used/alternative.html')
     128            render_to_string('template_used/base.html')
     129
     130    def test_not_used(self):
     131        with self.assertTemplateNotUsed('template_used/base.html'):
     132            pass
     133        with self.assertTemplateNotUsed('template_used/alternative.html'):
     134            pass
     135
     136    def test_error_message(self):
     137        try:
     138            with self.assertTemplateUsed('template_used/base.html'):
     139                pass
     140        except AssertionError, e:
     141            self.assertTrue('template_used/base.html' in e.message)
     142
     143        try:
     144            with self.assertTemplateUsed(template_name='template_used/base.html'):
     145                pass
     146        except AssertionError, e:
     147            self.assertTrue('template_used/base.html' in e.message)
     148
     149        try:
     150            with self.assertTemplateUsed('template_used/base.html'):
     151                render_to_string('template_used/alternative.html')
     152        except AssertionError, e:
     153            self.assertTrue('template_used/base.html' in e.message, e.message)
     154            self.assertTrue('template_used/alternative.html' in e.message, e.message)
     155
     156    def test_failure(self):
     157        with self.assertRaises(TypeError):
     158            with self.assertTemplateUsed():
     159                pass
     160
     161        with self.assertRaises(AssertionError):
     162            with self.assertTemplateUsed(''):
     163                pass
     164
     165        with self.assertRaises(AssertionError):
     166            with self.assertTemplateUsed(''):
     167                render_to_string('template_used/base.html')
     168
     169        with self.assertRaises(AssertionError):
     170            with self.assertTemplateUsed(template_name=''):
     171                pass
     172
     173        with self.assertRaises(AssertionError):
     174            with self.assertTemplateUsed('template_used/base.html'):
     175                render_to_string('template_used/alternative.html')
     176
     177
    91178class SaveRestoreWarningState(TestCase):
    92179    def test_save_restore_warnings_state(self):
    93180        """
Back to Top