38

I'm adding a set of template tags to a Django application and I'm not sure how to test them. I've used them in my templates and they seem to be working but I was looking for something more formal. The main logic is done in the models/model managers and has been tested. The tags simply retrieve data and store it in a context variable such as

{% views_for_object widget as views %}
"""
Retrieves the number of views and stores them in a context variable.
"""
# or
{% most_viewed_for_model main.model_name as viewed_models %}
"""
Retrieves the ViewTrackers for the most viewed instances of the given model.
"""

So my question is do you typically test your template tags and if you do how do you do it?

Dominic Rodger
  • 90,548
  • 30
  • 192
  • 207
Mark Lavin
  • 22,998
  • 4
  • 71
  • 67

5 Answers5

37

This is a short passage of one of my test files, where self.render_template a simple helper method in the TestCase is:

    rendered = self.render_template(
        '{% load templatequery %}'
        '{% displayquery django_templatequery.KeyValue all() with "list.html" %}'
    )
    self.assertEqual(rendered,"foo=0\nbar=50\nspam=100\negg=200\n")

    self.assertRaises(
        template.TemplateSyntaxError,
        self.render_template,
        '{% load templatequery %}'
        '{% displayquery django_templatequery.KeyValue all() notwith "list.html" %}'
    )

It is very basic and uses blackbox testing. It just takes a string as template source, renders it and checks if the output equals the expected string.

The render_template method is quite simplistic:

from django.template import Context, Template

class MyTest(TestCase):
    def render_template(self, string, context=None):
        context = context or {}
        context = Context(context)
        return Template(string).render(context)
Gregor Müllegger
  • 4,673
  • 1
  • 21
  • 22
  • How do you test this outside of a project scope, say, for a reusable app? Rendering a template string that include `{% load custom_tag %}` does not seem to work, at least without additional work? – Santa Apr 23 '10 at 19:40
  • 3
    Answered my own question: use `register = template.Library(); template.libraries['django.templatetags.mytest'] = register; register.tag(name='custom_tag', compile_function=custom_tag)`. – Santa Apr 23 '10 at 20:15
  • 2
    what is `self` in your code sample? `My TestCase` object does not have `render_template` method – Sashko Lykhenko Jan 25 '15 at 13:37
  • @Gregor Müllegger could you please update your answer and include the `render_template` method? thanks – yamm Jun 04 '15 at 14:18
  • @yamm: I just added a snippet containing the `render_template` method. Hope this helps. – Gregor Müllegger Jun 28 '15 at 10:15
21

You guys got me on the right track. It's possible to check that the context was correctly changed after the render:

class TemplateTagsTestCase(unittest.TestCase):        
    def setUp(self):    
        self.obj = TestObject.objects.create(title='Obj a')

    def testViewsForOjbect(self):
        ViewTracker.add_view_for(self.obj)
        t = Template('{% load my_tags %}{% views_for_object obj as views %}')
        c = Context({"obj": self.obj})
        t.render(c)
        self.assertEqual(c['views'], 1)
Mark Lavin
  • 22,998
  • 4
  • 71
  • 67
10

A good example of how to test template tags test of flatpage templatetags

nnyby
  • 4,125
  • 8
  • 45
  • 95
Neil
  • 7,565
  • 8
  • 38
  • 48
0

Strings can be rendered as templates, so you could write a test that includes a simple 'template' using your templatetag as a string and just make sure it renders correctly given a certain context.

Josh Ourisman
  • 1,032
  • 1
  • 8
  • 15
  • These tags only render an empty string and instead change the context but I should be able to test for that as well. – Mark Lavin Nov 06 '09 at 15:31
0

When I was testing my template tags, I would have the tag, itself, return a string containing the text or dict I was working with ... sort of along the lines of the other suggestion.

Since tags can modify the context and/or return a string to be rendered -- I found it was fastest just to view the rendered string.

Instead of:

return ''

Have it:

return str(my_data_that_I_am_testing)

Until you are happy.

thornomad
  • 6,107
  • 10
  • 43
  • 72