Note that there are some explanatory texts on larger screens.

plurals
  1. PODependency injection in (Python) Google App Engine
    primarykey
    data
    text
    <p>I want to achieve maximum testability in my <a href="http://en.wikipedia.org/wiki/YAML" rel="nofollow">Google App Engine</a> app which I'm writing in Python.</p> <p>Basically what I'm doing is creating an all-purpose base handler which inherits the <code>google.appengine.ext.webapp.RequestHandler</code>. My base handler will expose common functionality in my app such as repository functions, a session object and the like.</p> <p>When the <code>WSGIApplication</code> receives a request it will find the handler class that has been registered for the requested URL, and call its constructor and after that it will call a method called <code>initialize</code> passing in the <code>request</code> and <code>response</code> objects. </p> <p>Now, for the sake of testability I want to be able to "<em>mock</em>" these objects (along with my own objects). So my question is how do I go about injecting these mocks? I can override the <code>initialize</code> method in my base handler and check for some global "test flag" and initialize some dummy <code>request</code> and <code>response</code> objects. But it seems wrong (in <em>my</em> mind at least). And how do I go about initializing my other objects (which may depend on the <code>request</code> and <code>response</code> objects)?</p> <p>As you can probably tell I'm a little new to Python so any recommendations would be most welcome.</p> <p><strong>EDIT:</strong></p> <p>It has been pointed out to me that this question was a little hard to answer without some code, so here goes:</p> <pre><code>from google.appengine.ext import webapp from ..utils import gmemsess from .. import errors _user_id_name = 'userid' class Handler(webapp.RequestHandler): ''' classdocs ''' def __init__(self): ''' Constructor ''' self.charset = 'utf8' self._session = None def _getsession(self): if not self._session: self._session = gmemsess.Session(self) return self._session def _get_is_logged_in(self): return self.session.has_key(_user_id_name) def _get_user_id(self): if not self.is_logged_in: raise errors.UserNotLoggedInError() return self.session[_user_id_name] session = property(_getsession) is_logged_in = property(_get_is_logged_in) user_id = property(_get_user_id) </code></pre> <p>As you can see, no dependency injection is going on here at all. The session object is created by calling <code>gmemsess.Session(self)</code>. The <code>Session</code> class expects a class which has a <code>request</code> object on it (it uses this to read a cookie value). In this case, <code>self</code> does have such a property since it inherits from <code>webapp.RequestHandler</code>. It also only has the object on it because after calling (the empty) constructor, <code>WSGIApplication</code> calls a method called <code>initialize</code> which sets this object (and the response object). The initialize method is declared on the base class (<code>webapp.RequestHandler</code>). It looks like this:</p> <pre><code>def initialize(self, request, response): """Initializes this request handler with the given Request and Response.""" self.request = request self.response = response </code></pre> <p>When a request is made, the <code>WSGIApplication</code> class does the following:</p> <pre><code>def __call__(self, environ, start_response): """Called by WSGI when a request comes in.""" request = self.REQUEST_CLASS(environ) response = self.RESPONSE_CLASS() WSGIApplication.active_instance = self handler = None groups = () for regexp, handler_class in self._url_mapping: match = regexp.match(request.path) if match: handler = handler_class() handler.initialize(request, response) groups = match.groups() break self.current_request_args = groups if handler: try: method = environ['REQUEST_METHOD'] if method == 'GET': handler.get(*groups) elif method == 'POST': handler.post(*groups) '''SNIP''' </code></pre> <p>The lines of interest are those that say:</p> <pre><code> handler = handler_class() handler.initialize(request, response) </code></pre> <p>As you can see, it calls the empty constructor on my handler class. And this is a problem for me, because what I think I would like to do is to inject, at runtime, the type of my session object, such that my class would look like this instead (fragment showed):</p> <pre><code> def __init__(self, session_type): ''' Constructor ''' self.charset = 'utf8' self._session = None self._session_type = session_type def _getsession(self): if not self._session: self._session = self._session_type(self) return self._session </code></pre> <p>However I can't get my head around how I would achieve this, since the <code>WSGIApplication</code> only calls the empty constructor. I guess I could register the <code>session_type</code> in some global variable, but that does not really follow the philosophy of dependency injection (as I understand it), but as stated I'm new to Python, so maybe I'm just thinking about it the wrong way. In any event I would rather pass in a session object instead of it's type, but this looks kind of impossible here.</p> <p>Any input is appreciated. </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload