-->

Unittest Jinja2 and Webapp2 : template not found

2019-07-12 13:19发布

问题:

I use Jinja2 with Webapp2 on a GAE project.

I have a base RequestHandler as describe in webapp2_extras.jinja2:

import webapp2

from webapp2_extras import jinja2


def jinja2_factory(app):
    """Set configuration environment for Jinja."""
    config = {my config...}
    j = jinja2.Jinja2(app, config=config)
    return j


class BaseHandler(webapp2.RequestHandler):

    @webapp2.cached_property
    def jinja2(self):
        # Returns a Jinja2 renderer cached in the app registry.
        return jinja2.get_jinja2(factory=jinja2_factory, app=self.app)

    def render_response(self, _template, **context):
        # Renders a template and writes the result to the response.
        rv = self.jinja2.render_template(_template, **context)
        self.response.write(rv)

And a view handler as:

class MyHandler(BaseHandler):
    def get(self):
        context = {'message': 'Hello, world!'}
        self.render_response('my_template.html', **context)

My templates are in the default location (templates).

The app works well on dev server, and the template is correctly rendered.

But when I try to unittest MyHandler with

import unittest
import webapp2
import webstest

class MyHandlerTest(unittest.TestCase):

    def setUp(self):
        application = webapp2.WSGIApplication([('/', MyHandler)])
        self.testapp = webtest.TestApp(application)

    def test_response(self):
        response = application.get_response('/')
        ...

application.get_response('/my-view') raise an exception: TemplateNotFound: my_template.html.

Is there something I missed? Like a jinja2 environment or template loader configuration?

回答1:

Problem origin: Jinja2 default loader searches files in a relative ./templates/ directory. When you run your GAE application on the development server this path is relative to the root of your application. But when you run your unittests this path is relative to your unittest files.

Solution: Not really an ideal solution, but here a trick I did to solve my problem.

I updated the jinja2 factory to add a dynamic template path, set in app config:

def jinja2_factory(app):
    """Set configuration environment for Jinja."""
    config = {'template_path': app.config.get('templates_path', 'templates'),}
    j = jinja2.Jinja2(app, config=config)
    return j

And I set an absolute path to the templates in the setUp of my unittests:

class MyHandlerTest(unittest.TestCase):

    def setUp(self):
        # Set template path for loader
        start = os.path.dirname(__file__)
        rel_path = os.path.join(start, '../../templates') # Path to my template
        abs_path = os.path.realpath(rel_path)
        application.config.update({'templates_path': abs_path})