Python InvalidModuleError()在使用Testbed对Google应用程序引擎进行单元测试时

Python InvalidModuleError()在使用Testbed对Google应用程序引擎进行单元测试时,python,google-app-engine,Python,Google App Engine,当我试图为一个由多个模块组成的GoogleAppEngine应用程序编写一些Python单元测试时,我遇到了几个错误 我一直在遵循上节给出的指导 首先,我得到以下信息: 错误:root:AssertionError('未找到服务“模块”的api代理,) 然而,我确定这是因为我没有正确初始化测试床,需要单独呼叫: self.testbed.init_modules_stub() 这是尽管已经呼吁: self.testbed.init_all_stubs() 这对我来说似乎很奇怪,但不是主要问题

当我试图为一个由多个模块组成的GoogleAppEngine应用程序编写一些Python单元测试时,我遇到了几个错误

我一直在遵循上节给出的指导

首先,我得到以下信息:

错误:root:AssertionError('未找到服务“模块”的api代理,)

然而,我确定这是因为我没有正确初始化测试床,需要单独呼叫:

self.testbed.init_modules_stub()
这是尽管已经呼吁:

self.testbed.init_all_stubs()
这对我来说似乎很奇怪,但不是主要问题。。。现在我已经克服了这个错误,取而代之的是:

错误:根: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)
我可以看到“队列”已使用模块名称正确初始化

google_appengine中来自get_hostname()状态的注释:

“提出: 如果给定的moduleversion无效,则InvalidModuleError。“

所以出于某种原因,我的模块转换是无效的

那么,在测试代码时,是否需要手动传递模块版本以获取_hostname()

还是我未能以某种方式初始化测试台以确保模块的版本有效?

编辑:我继续研究这个问题,并通过Google应用程序引擎代码追踪到
请求_info.py
中的类
\u LocalFakeDispatcher
。该类设置了一些用于测试的默认值。问题是,我的测试到达这里试图确定模块是否有效,但它与此存根中的默认值之一不匹配,因此最终返回一个无效模块错误

是否有某种方法可以覆盖此dispatcher中的默认设置,以使用预期的模块名称和版本进行设置?

见:

非常感谢

R

$gcloud——谷歌云SDK 0.9.44版

app 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_u.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)
当然,假设这些是您想要的模块名称和版本

是的,它肯定会变得更容易(测试床或一些模块应该公开一个函数来实现这一点——最好是通过解析适当的
yaml
文件,但至少要有显式参数),非常重要的是,它应该有很好的文档记录

作为五年前testbed第一个版本的先驱的第一作者,我个人为没有关注它而道歉(对不起,我当时正忙于不同的工作!——但是,作为一个对单元测试的狂热者,我应该在这方面花费大约20%的时间)


请务必打开一个功能请求,以便很好地公开此内容并对其进行记录,感谢您的耐心和您出色的“侦探工作”,找出问题的症结所在

非常感谢您的详细回答和评论。你的建议很有效;正是我想要的。我将按照您的建议花时间提出功能请求。再次感谢。@rdc您能否将功能请求链接到此处,以便将来搜索?@Trii我已打开功能请求:谢谢@rdc!我使用您实际的模块定义基于@Alex的答案NoseGAE实现了一个解决方案:对我来说,它不起作用。您需要使用dev_appserver运行服务吗?或者更优选地,从单元测试代码中分派服务,以便它们使用相同的数据存储存根。
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)