Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to unittest the template variables passed to jinja2 template from webapp2 request handler

I'm trying to test my webapp2 handlers. To do this, I thought it would be a good idea to send a request to the handler e.g.:

request = webapp2.Request.blank('/')
# Get a response for that request.
response = request.get_response(main.app)

The problem is, response is mostly just a bunch of HTML etc.

I want to look at what was passed to my jinja2 template from the handler before it was turned into HTML.

I want my test to get at the state within the handler class code. I wan't to be able to see what certain variables looked like in the response handler, and then I want to see what the dict templates looks like before it was passed to render_to_response()

I want to test these variables have the correct values.

Here is my test code so far, but I'm stuck because response = request.get_response() just gives me a bunch of html and not the raw variables.

import unittest
import main
import webapp2

class DemoTestCase(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def testNothing(self):
        self.assertEqual(42, 21 + 21)

    def testHomeHandler(self):
        # Build a request object passing the URI path to be tested.
        # You can also pass headers, query arguments etc.
        request = webapp2.Request.blank('/')
        # Get a response for that request.
        response = request.get_response(main.app)

        # Let's check if the response is correct.
        self.assertEqual(response.status_int, 200)
        self.assertEqual(response.body, 'Hello, world!')


if __name__ == '__main__':
    unittest.main()

and here is my handler:

class HomeHandler(BaseHandler):
    def get(self, file_name_filter=None, category_filter=None):
        file_names = os.listdir('blog_posts')
        blogs = []

        get_line = lambda file_: file_.readline().strip().replace("<!--","").replace("-->","")

        for fn in file_names:
            with open('blog_posts/%s' % fn) as file_:
                heading = get_line(file_)
                link_name = get_line(file_)
                category = get_line(file_)

            date_ = datetime.strptime(fn.split("_")[0], "%Y%m%d")

            blog_dict = {'date': date_, 'heading': heading,
                         'link_name': link_name,
                         'category': category,
                         'filename': fn.replace(".html", ""),
                         'raw_file_name': fn}

            blogs.append(blog_dict)

        categories = Counter(d['category'] for d in blogs)
        templates = {'categories': categories,
                     'blogs': blogs,
                     'file_name_filter': file_name_filter,
                     'category_filter': category_filter}

        assert(len(file_names) == len(set(d['link_name'] for d in blogs)))

        self.render_template('home.html', **templates)

and here is my basehandler:

class BaseHandler(webapp2.RequestHandler):
    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

    def render_template(self, filename, **kwargs):
        #kwargs.update({})
        #TODO() datastore caching here for caching of (handlername, handler parameters, changeable parameters, app_upload_date)
        #TODO() write rendered page to its own html file, and just serve that whole file. (includes all posts). JQuery can show/hide posts.
        self.response.write(self.jinja2.render_template(filename, **kwargs))

Perhaps I have got the wrong idea of how to do unit testing, or perhaps I should have written my code in a way that makes it easier to test? or is there some way of getting the state of my code?

Also if someone were to re-write the code and change the variable names, then the tests would break.

like image 839
robert king Avatar asked May 10 '12 03:05

robert king


2 Answers

You can mock BaseHandler.render_template method and test its parameters.

See this question for a list of popular Python mocking frameworks.

like image 52
proppy Avatar answered Nov 10 '22 18:11

proppy


Thanks to proppy's suggestion I ended up using a mock.

http://www.voidspace.org.uk/python/mock/

(mock is included as part or unittest.mock in python 3)

So here is my main.py code which is similar to what I have in webapp2:

note instead of BaseHandler.render_template i have BaseHandler.say_yo

__author__ = 'Robert'

print "hello from main"

class BaseHandler():
    def say_yo(self,some_number=99):
        print "yo"
        return "sup"

class TheHandler(BaseHandler):
    def get(self, my_number=42):
        print "in TheHandler's get()"
        print self.say_yo(my_number)
        return "TheHandler's return string"

and atest.py:

__author__ = 'Robert'

import unittest
import main
from mock import patch

class DemoTestCase(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def testNothing(self):
        self.assertEqual(42, 21 + 21)

    def testSomeRequests(self):
        print "hi"
        bh = main.BaseHandler()
        print bh.say_yo()

        print "1111111"

        with patch('main.BaseHandler.say_yo') as patched_bh:
            print dir(patched_bh)
            patched_bh.return_value = 'double_sup'
            bh2 = main.BaseHandler()
            print bh2.say_yo()
            print "222222"

        bh3 = main.BaseHandler()
        print bh3.say_yo()

        print "3333"

        th = main.TheHandler()
        print th.get()

        print "44444"
        with patch('main.BaseHandler.say_yo') as patched_bh:
            patched_bh.return_value = 'last_sup'
            th = main.TheHandler()
            print th.get()
            print th.get(123)
            print "---"
            print patched_bh.called
            print patched_bh.call_args_list
            print "555555"



if __name__ == '__main__':
    unittest.main()

this code gives lots of output, here is a sample:

44444
in TheHandler's get()
last_sup
TheHandler's return string
in TheHandler's get()
last_sup
TheHandler's return string
---
True
[call(42), call(123)]
555555
like image 32
robert king Avatar answered Nov 10 '22 18:11

robert king