编程语言
首页 > 编程语言> > (Python)Google App Engine中的依赖注入

(Python)Google App Engine中的依赖注入

作者:互联网

我想在我用Python编写的Google App Engine应用程序中实现最大的可测试性.

基本上,我正在做的是创建一个通用的基本处理程序,该处理程序继承了google.appengine.ext.webapp.RequestHandler.我的基本处理程序将在我的应用程序中公开常用功能,例如存储库功能,会话对象等.

当WSGIApplication接收到请求时,它将找到已为请求的URL注册的处理程序类,并调用其构造函数,此后,它将调用一种称为initialize的方法,该方法将请求和响应对象传递.

现在,出于可测试性的考虑,我希望能够“模拟”这些对象(以及我自己的对象).所以我的问题是我该如何注入这些模拟?我可以在基本处理程序中重写initialize方法,并检查一些全局“测试标志”,并初始化一些虚拟请求和响应对象.但这似乎是错误的(至少在我看来).以及如何初始化其他对象(可能取决于请求和响应对象)?

如您所知,我是Python的新手,因此欢迎您提出任何建议.

编辑:

有人向我指出,没有一些代码,这个问题很难回答,所以去了:

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)

如您所见,这里根本没有进行依赖项注入.通过调用gmemsess.Session(self)创建会话对象. Session类需要一个带有请求对象的类(它使用该对象读取cookie值).在这种情况下,self确实具有这样的属性,因为它继承自webapp.RequestHandler.它也只有对象,因为在调用(空)构造函数之后,WSGIApplication调用了一个称为initialize的方法,该方法设置了该对象(和响应对象).初始化方法在基类(webapp.RequestHandler)上声明.
看起来像这样:

def initialize(self, request, response):
    """Initializes this request handler with the given Request and 
     Response."""
    self.request = request
    self.response = response

发出请求后,WSGIApplication类将执行以下操作:

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'''

感兴趣的行是那些说:

     handler = handler_class()
     handler.initialize(request, response)

如您所见,它在我的处理程序类上调用空的构造函数.这对我来说是个问题,因为我认为我想做的是在运行时注入会话对象的类型,以使我的类看起来像这样(显示片段):

    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

但是,由于WSGIApplication只调用空的构造函数,所以我无法理解该如何实现.我想我可以在一些全局变量中注册session_type,但这并没有真正遵循依赖注入的原理(据我了解),但是正如我所说的,我是Python的新手,所以也许我只是在考虑它错误道.无论如何,我都希望传递一个会话对象而不是它的类型,但这在这里看起来是不可能的.

任何输入表示赞赏.

解决方法:

实现所需目标的最简单方法是创建一个模块级变量,其中包含要创建的会话的类:

# myhandler.py
session_class = gmemsess.Session

class Handler(webapp.Request
    def _getsession(self):
        if not self._session:
            self._session = session_class(self)
        return self._session

然后,无论您在哪里进行测试和运行之间的决定:

import myhandler

if testing:
    myhandler.session_class = MyTestingSession

这使您的处理程序类几乎保持不变,使WSGIApplication完全保持不变,并为您提供了根据需要进行测试的灵活性.

标签:google-app-engine,dependency-injection,python
来源: https://codeday.me/bug/20191209/2096107.html