【问题标题】:Flask Testing in Python -- Building one API in a repo with many to unit test it via import_modulePython中的烧瓶测试——在一个repo中构建一个API,通过import_module对它进行单元测试
【发布时间】:2014-12-18 18:11:04
【问题描述】:

我们有一个 ETL 数据 API 存储库。我们在其中进行所有 etl 处理,然后在 API 中输出数据。这些 API 从将资源类传递到服务器以构建 API 的单个命令一次运行一个。资源类位于 __init__.py. 中的 web 目录中

这是一个很棒的约定,而且使用起来非常简单,但我遇到的问题是试图让 3 个可用的 API 之一进行测试。我们的目录结构是这样的(称项目'tomato')

tomato

- category_api
    - web
    - etl
    - test
        - here is where we are writing some tests (test_category_api.py)
    - data
- article_api
    - web
    - etl
    - test
    - data
- recommendation_api
    - web
    - etl
    - test
    - data
- common
    - common shit

在这个测试中,我有以下测试类。倒数第七行, 你会看到一条关于它在哪里中断的评论。它是import_module 方法。

    import unittest
    import sys
    import os
    import sys
    import json

    from importlib import import_module
    from flask import Flask
    from flask_restful import Api, abort, wraps
    from flask_restful.utils import cors
    from flask.ext.testing import TestCase

    #dir_above_top_level = os.path.join(os.path.abspath(__file__), '../../..    /')
    #sys.path.append(os.path.abspath(dir_above_top_level))

    _CATEGORY_ENDPOINT = '/v1/category/'
    _PACKAGE_NAME = os.environ['RECO_API_PACKAGE_NAME']
    _CORS = cors.crossdomain(origin='*',
                             headers=['Origin', 'X-Requested-With',
                                      'Content-Type', 'Accept'],
                             methods=['GET', 'HEAD', 'OPTIONS'],
                             max_age=3600)

    class CategoryTests(TestCase):
        def __init__(self):
            self.app = Flask(__name__)
            self._configure_app()
            for resource in self.resource_classes:
                self.api.add_resource(self.resource,
                                      self.resource.URI_TEMPLATE)
        def test_status_code(self):
            self.response = self.client.post(_CATEGORY_ENDPOINT,
                                         data=json.dumps(
                                         {'title': 'Enjoy this delicious food'}),
                                         headers=json.dumps(
                                         {'content-type':'application/json'}))
            self.assertEqual(self.response.status_code, 200)

        def test_version(self):
            self.response = self.client.post(_CATEGORY_ENDPOINT,
                                             data=json.dumps(
                                             {"title": "eat some delicious stuff"}),
                                             headers=json.dumps(
                                             {'content-type':'application/json'}))
            self.assertEqual(json.dumps(self.response['version']), '1')

        def _configure_app(self):
            self.app = Flask(__name__)
            self.app.config['TESTING'] = True
            self.app.debug = True
            self.decorators = [_CORS]
            self.app.Threaded = True
            self.web_package = 'tomato.category.web'
            self.package = import_module('.__init__', self.web_package) # WE BREAK HERE
            self.resources = package.RESOURCE_NAMES
            self.resource_classes = [ getattr(package, resource) for resource in resources ]
            self.api = Api(self.app, catch_all_404s=True, decorators=self.decorators)

    if __name__ == '__main__':
        unittest.main()

我们在运行这些测试时遇到了异常:

ImportError: No module named tomato.category.web.__init__

然而 cd 进入主顶层目录,ls tomato/category/web 得到我们__init__.py 和资源类。

如何导入此类,以便实例化 API 以在此类中运行测试? 或者,如果我完全走错了路,我应该怎么做?

【问题讨论】:

    标签: python unit-testing flask


    【解决方案1】:

    你不需要导入__init__,就像你可能不会导入from tomato.category.web import __init__一样。您应该可以直接导入web 包。

    self.web_package = 'tomato.category.web'
    self.package = import_module(self.web_package)
    

    【讨论】:

    • 您的意思是import_module 而不是import_lib?我想了很多,所以我把它改成了那个(import_lib 不存在我以任何方式使用的导入)。然而,我确实按照说明运行了它并得到了输出:文件"/usr/local/Cellar/python/2.7.8/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py", line 37, in import_module __import__(name) ImportError: No module named tomato.category.web
    • 是的,很抱歉。
    • 如果solomon 不是tomato 的真名,那是你的问题。但是,假设它是,听起来solomon 不在您的路径中。您如何以及从哪个目录运行测试?
    • 没问题,感谢您的回复!可悲的是,当我以这种方式运行它时,我仍然收到先前评论中引用的错误。啊。这可能与当前的抽象路径有关还是它看不到它?
    • 我在 repo 中使用了假名,真名是所罗门。编辑。
    【解决方案2】:

    这里的问题在于目录结构。在目前的道路上,我不在顶层。它是一个模块。所以需要的是取消注释顶部的两行,并更改结构以附加这样的路径。

    dir_above_top_level = os.path.join(os.path.abspath(__file__), '../../../..')
    sys.path.append(os.path.abspath(dir_above_top_level))
    

    现在,我可以使用

    self.web_package = 'tomato.category.web'
    self.package = import_module('.__init__', self.web_package)
    

    现在它可以正常导入,我可以抓取资源类来设置测试 API

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-09
      • 1970-01-01
      • 1970-01-01
      • 2014-03-12
      • 1970-01-01
      • 1970-01-01
      • 2013-02-26
      相关资源
      最近更新 更多