使用 Testbed 进行单元测试时的 InvalidModuleError() Google App Engine
InvalidModuleError() when using Testbed to Unit Test Google App Engine
在尝试为包含多个模块的 Google App Engine 应用程序编写一些 Python 单元测试时,我一直在努力解决一些错误。
我一直在遵循 https://cloud.google.com/appengine/docs/python/tools/localunittesting
上给出的指导
首先我得到以下信息:
ERROR:root:AssertionError('No api proxy found for service "modules"’,)
但是我确定这是因为我没有正确初始化 Testbed,需要单独调用:
self.testbed.init_modules_stub()
尽管已经调用了:
self.testbed.init_all_stubs()
这对我来说似乎很奇怪,但这不是主要问题......现在我已经克服了那个错误,而是得到:
ERROR:root:InvalidModuleError()
代码非常简单。以下是测试用例的相关部分:
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
self.testbed.init_all_stubs
self.testbed.init_modules_stub()
def test_should_submit_a_task(self):
post_content = '{ "bucket": "/test/", "filename", "test", "operation": "read" }'
request = webapp2.Request.blank('/path/to/module/method', POST=post_content)
response = request.get_response(main.application)
self.assertEquals(response.status_int, 200)
被测代码中报错的行如下:
host = get_hostname(queue)
我可以看到 'queue' 已使用模块名称正确初始化。
来自 get_hostname() 的 google_appengine 中的评论状态:
”提出:
InvalidModuleError 如果给定的模块版本无效。"
所以出于某种原因我的模块版本无效。
那么,在测试代码的时候,是否需要手动传递一个模块版本给get_hostname()?
还是我未能以某种方式初始化测试台以确保模块的版本有效?
编辑:我继续致力于此,并通过 Google App Engine 代码追踪到 class _LocalFakeDispatcher
在 request_info.py
中。 class 设置了一些用于测试的默认值。问题是,我的测试到达这里试图确定模块是否有效,但它与此存根中的默认值之一不匹配,因此最终返回无效模块错误。
有什么方法可以覆盖此调度程序中的默认值,以设置它填充预期的模块名称和版本?
参见:
class _LocalFakeDispatcher(Dispatcher):
"""A fake Dispatcher implementation usable by tests."""
def __init__(self,
module_names=None,
module_name_to_versions=None,
module_name_to_default_versions=None,
module_name_to_version_to_hostname=None):
super(_LocalFakeDispatcher, self).__init__()
if module_names is None:
module_names = ['default']
if module_name_to_versions is None:
module_name_to_versions = {'default': ['1']}
etc. ...
非常感谢
R.
$gcloud --version Google 云 SDK 0.9.44
应用2015.01.15
app-engine-go-darwin-x86_64 1.9.17
应用引擎-java 1.9.17
应用程序引擎管理的虚拟机 2014.11.03
应用引擎-python 1.9.17
等等
需要调用 init_modules_stub
的问题与您拥有的 SDK 版本(以及 testbed/__init__.py
)有关;在当前版本中已将其添加到 init_all_stubs
(不确定确切时间),因此升级应该可以让您消除显式调用的需要。但正如你所说,这不是主要问题。
但是关于更实质性的问题——据我所知,您没有做错任何事,因为没有文档说明您应该做任何特别的事情来初始化模块的存根。
幸运的是,变通方法并不太糟糕。具体来说,您可以在单元测试代码的早期进行初始化:
from google.appengine.api import request_info
# edit all_versions per modules & versions thereof needing tests
all_versions = {'default':[1], 'andsome':[2], 'others':[1]}
def_versions = {m:all_versions[m][0] for m in all_versions}
m2h = {m:{def_versions[m]:'localhost:8080'} for m in def_versions}
request_info._local_dispatcher = request_info._LocalFakeDispatcher(
module_names = list(all_versions),
module_name_to_versions = all_versions,
module_name_to_default_versions = def_versions,
module_name_to_version_to_hostname = m2h)
当然假设这些是您想要的模块名称和版本!
是的,它应该 绝对 更容易(测试平台或 some 模块应该暴露一个函数来做这个——理想情况下通过解析适当的yaml
个文件,但至少有显式参数) 和 ,非常重要的是,它应该被详细记录。
我是五年前 testbed 第一个版本的前身的第一作者,我个人很抱歉没有关注它(抱歉——我 当时 忙于非常同时做不同的工作!--但是,作为一个单元测试的狂热者,我应该在这上面花费大约 20% 的时间。
请打开一个关于很好地公开并记录它的功能请求,感谢您的耐心和出色的 "detective work" 识别问题的关键!
在尝试为包含多个模块的 Google App Engine 应用程序编写一些 Python 单元测试时,我一直在努力解决一些错误。
我一直在遵循 https://cloud.google.com/appengine/docs/python/tools/localunittesting
上给出的指导首先我得到以下信息:
ERROR:root:AssertionError('No api proxy found for service "modules"’,)
但是我确定这是因为我没有正确初始化 Testbed,需要单独调用:
self.testbed.init_modules_stub()
尽管已经调用了:
self.testbed.init_all_stubs()
这对我来说似乎很奇怪,但这不是主要问题......现在我已经克服了那个错误,而是得到:
ERROR:root:InvalidModuleError()
代码非常简单。以下是测试用例的相关部分:
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
self.testbed.init_all_stubs
self.testbed.init_modules_stub()
def test_should_submit_a_task(self):
post_content = '{ "bucket": "/test/", "filename", "test", "operation": "read" }'
request = webapp2.Request.blank('/path/to/module/method', POST=post_content)
response = request.get_response(main.application)
self.assertEquals(response.status_int, 200)
被测代码中报错的行如下:
host = get_hostname(queue)
我可以看到 'queue' 已使用模块名称正确初始化。
来自 get_hostname() 的 google_appengine 中的评论状态:
”提出: InvalidModuleError 如果给定的模块版本无效。"
所以出于某种原因我的模块版本无效。
那么,在测试代码的时候,是否需要手动传递一个模块版本给get_hostname()?
还是我未能以某种方式初始化测试台以确保模块的版本有效?
编辑:我继续致力于此,并通过 Google App Engine 代码追踪到 class _LocalFakeDispatcher
在 request_info.py
中。 class 设置了一些用于测试的默认值。问题是,我的测试到达这里试图确定模块是否有效,但它与此存根中的默认值之一不匹配,因此最终返回无效模块错误。
有什么方法可以覆盖此调度程序中的默认值,以设置它填充预期的模块名称和版本?
参见:
class _LocalFakeDispatcher(Dispatcher):
"""A fake Dispatcher implementation usable by tests."""
def __init__(self,
module_names=None,
module_name_to_versions=None,
module_name_to_default_versions=None,
module_name_to_version_to_hostname=None):
super(_LocalFakeDispatcher, self).__init__()
if module_names is None:
module_names = ['default']
if module_name_to_versions is None:
module_name_to_versions = {'default': ['1']}
etc. ...
非常感谢
R.
$gcloud --version Google 云 SDK 0.9.44
应用2015.01.15 app-engine-go-darwin-x86_64 1.9.17 应用引擎-java 1.9.17 应用程序引擎管理的虚拟机 2014.11.03 应用引擎-python 1.9.17 等等
需要调用 init_modules_stub
的问题与您拥有的 SDK 版本(以及 testbed/__init__.py
)有关;在当前版本中已将其添加到 init_all_stubs
(不确定确切时间),因此升级应该可以让您消除显式调用的需要。但正如你所说,这不是主要问题。
但是关于更实质性的问题——据我所知,您没有做错任何事,因为没有文档说明您应该做任何特别的事情来初始化模块的存根。
幸运的是,变通方法并不太糟糕。具体来说,您可以在单元测试代码的早期进行初始化:
from google.appengine.api import request_info
# edit all_versions per modules & versions thereof needing tests
all_versions = {'default':[1], 'andsome':[2], 'others':[1]}
def_versions = {m:all_versions[m][0] for m in all_versions}
m2h = {m:{def_versions[m]:'localhost:8080'} for m in def_versions}
request_info._local_dispatcher = request_info._LocalFakeDispatcher(
module_names = list(all_versions),
module_name_to_versions = all_versions,
module_name_to_default_versions = def_versions,
module_name_to_version_to_hostname = m2h)
当然假设这些是您想要的模块名称和版本!
是的,它应该 绝对 更容易(测试平台或 some 模块应该暴露一个函数来做这个——理想情况下通过解析适当的yaml
个文件,但至少有显式参数) 和 ,非常重要的是,它应该被详细记录。
我是五年前 testbed 第一个版本的前身的第一作者,我个人很抱歉没有关注它(抱歉——我 当时 忙于非常同时做不同的工作!--但是,作为一个单元测试的狂热者,我应该在这上面花费大约 20% 的时间。
请打开一个关于很好地公开并记录它的功能请求,感谢您的耐心和出色的 "detective work" 识别问题的关键!