(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