【问题标题】:InvalidModuleError() when using Testbed to Unit Test Google App Engine使用 Testbed 对 Google App Engine 进行单元测试时出现 InvalidModuleError()
【发布时间】:2015-01-30 11:42:46
【问题描述】:

在尝试为包含多个模块的 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()

这对我来说似乎很奇怪,但不是主要问题......现在我已经克服了这个错误,而是得到了:

错误: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)

我可以看到“队列”已正确初始化为模块名称。

google_appengine 中的 cmets 来自 get_hostname() 状态:

“引发: 如果给定的模块版本无效,则 InvalidModuleError。"

所以由于某种原因我的模块版本无效。

那么,在测试代码时是否需要手动将模块版本传递给get_hostname()?

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

编辑:我一直在努力解决这个问题,并通过 Google App Engine 代码跟踪到 request_info.py 中的 _LocalFakeDispatcher 类。该类设置了一些用于测试的默认值。问题是,我的测试到达这里试图确定模块是否有效,但它与此存根中的默认值之一不匹配,因此最终返回无效模块错误。

是否可以通过某种方式覆盖此调度程序中的默认值,以将其设置为填充预期的模块名称和版本?

见:

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 谷歌云 SDK 0.9.44

应用程序 2015.01.15 app-engine-go-darwin-x86_64 1.9.17 应用引擎 Java 1.9.17 app-engine-managed-vms 2014.11.03 应用引擎-python 1.9.17 等等

【问题讨论】:

    标签: python google-app-engine


    【解决方案1】:

    需要调用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% 的时间。

    请打开一个功能请求,以很好地公开并记录它,感谢您的耐心和您出色的“侦探工作”找出问题的症结!

    【讨论】:

    • 非常感谢您的详细回答和 cmets。您的建议非常有效;正是我想要的。我会按照您的建议花时间提出功能请求。再次感谢。
    • @rdc 您能否在此处链接功能请求以供将来搜索?
    • 谢谢@rdc!我使用您的实际模块定义实现了基于@Alex 的答案 NoseGAE 的解决方案:github.com/Trii/NoseGAE/blob/…
    • 对我来说它不起作用。您是否需要使用 dev_appserver 运行该服务?或者更优选地,从单元测试代码中分派服务,以便它们使用相同的数据存储存根。
    猜你喜欢
    • 2016-11-22
    • 1970-01-01
    • 1970-01-01
    • 2011-09-04
    • 1970-01-01
    • 1970-01-01
    • 2013-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多