【问题标题】:Running flask server, nosetests and coverage运行烧瓶服务器、鼻子测试和覆盖率
【发布时间】:2015-07-11 01:29:55
【问题描述】:

我正在用 Flask 编写一个 api。我有几个返回 json 响应的视图,并且我编写了一些单元测试来检查这些视图是否正常工作并返回正确的数据。然后我打开了鼻子测试的覆盖插件(在我的例子中是nose-cov)。

这就是我的问题开始的地方,覆盖范围没有看到我的视图被测试执行。

首先一些基本代码给你完整的图片:

我的看法:

def get_user(uid):
    """Retrieve user.

    Args:
        uid (url): valid uid value

    Usage: ::

        GET user/<uid>/

    Returns:
      obj:
       ::

        {
            'data': {
                `response.User`,
            },
            'success': True,
            'status': 'get'
        }
    """
    if not uid:
        raise exception.ValueError("Uid is empty")

    obj = db_layer.user.get_user(uid=value)

    return {
        'data': {
            obj.to_dict(),  # to_dict is helper method that converts part of orm into dict
        },
        'success': True,
        'status': 'get'
    }

我的测试:

class TestUserViews(base.TestViewsBase):
    def test_get_user(self):
        uid = 'some_uid_from_fixtures'
        name = 'some_name_from_fixtures'

        response = self.get(u'user/uid/{}/'.format(uid))
        self.assertEqual(response.status_code, 200)

        user_data = json.loads(response.text)['data']
        self.assertEqual(name, user_data['username'])
        self.assertEqual(uid, user_data['uid'])

    def get(self, method, headers=None):
        """
        Wrapper around requests.get, reassures that authentication is
        sorted for us.
        """
        kwargs = {
            'headers': self._build_headers(headers),
        }

        return requests.get(self.get_url(method), **kwargs)

    def get_url(self, method):
        return '{}/{}/{}'.format(self.domain, self.version, method)

    def _build_headers(self, headers=None):
        if headers is None:
            headers = {}

        headers.update({
            'X-Auth-Token': 'some-token',
            'X-Auth-Token-Test-User-Id': 'some-uid',
        })

        return headers

为了运行测试套件,我有一个特殊的 shell 脚本,可以为我执行一些操作:

#!/usr/bin/env bash

HOST="0.0.0.0"
PORT="5001"

ENVS="PYTHONPATH=$PYTHONPATH:$PWD"

# start server 
START_SERVER="$ENVS python $PWD/server.py --port=$PORT --host=$HOST"

eval "$START_SERVER&"

PID=$!

eval "$ENVS nosetests -s --nologcapture --cov-report html --with-cov"

kill -9 $PID

在该视图被报告为未执行之后。

【问题讨论】:

    标签: python flask code-coverage nosetests


    【解决方案1】:

    好的,12 小时后我找到了解决方案。我检查了烧瓶、werkzeug、请求、子进程和线程库。只学习那个问题是在别处。解决方案其实很简单。必须修改的代码是 server.py 的执行。我们也需要覆盖它,然后合并 server.py 生成的结果和nosetests 生成的结果。修改后的 test-runner.sh 如下:

    #!/usr/bin/env bash
    
    HOST="0.0.0.0"
    PORT="5001"
    
    ENVS="COVERAGE_PROCESS_START=$PWD/.apirc PYTHONPATH=$PYTHONPATH:$PWD"
    
    START_SERVER="$ENVS coverage run --rcfile=.apirc $PWD/server.py --port=$PORT --host=$HOST"
    
    eval "$START_SERVER&"
    
    eval "$ENVS nosetests -s --nologcapture --cov-config=.apirc --cov-report html --with-cov"
    
    # this is important bit, we have to stop flask server gracefully otherwise
    # coverage won't get a chance to collect and save all results
    eval "curl -X POST http://$HOST:$PORT/0.0/shutdown/"
    
    # this will merge results from both coverage runs
    coverage combine  --rcfile=.apirc
    coverage html --rcfile=.apirc
    

    在我的例子中 .apirc 如下所示:

    [run]
    branch = True
    parallel = True
    source = files_to_cover/
    
    [html]
    directory = cover
    

    我们需要做的最后一件事是构建到我们的烧瓶中,该视图将使我们能够优雅地关闭服务器。以前我用 kill -9 蛮力杀死它,它不仅会杀死服务器,还会杀死覆盖范围。

    关注这个sn-p:http://flask.pocoo.org/snippets/67/

    而我的看法是这样的:

    def shutdown():
        if config.SHUTDOWN_ALLOWED:
            func = request.environ.get('werkzeug.server.shutdown')
            if func is None:
                raise RuntimeError('Not running with the Werkzeug Server')
            func()
    
            return 'Server shutting down...'
    

    使用nose-cov 代替标准覆盖插件很重要,因为它使用rcfile 并允许配置更多。在我们的例子中,并行是关键,请注意 data_files 变量不适用于鼻子覆盖,所以你不能在 .apirc 中覆盖它,你必须使用默认值。

    在所有这些之后,您的覆盖范围将几乎闪耀着有效的价值。

    我希望它对那里的人有所帮助。

    【讨论】:

    • 你能分享你实现这个的github存储库吗
    • 好吧,部分我可以,我现在正在开发一套基于烧瓶构建的工具,默认情况下执行此技巧:github.com/Drachenfels/magicarp-api,但这是正在进行的工作,因此文档是瘦,如果有任何问题,请毫不犹豫地问我一个问题,作为旁注,如果您 git clone 存储库,您可以尝试 ./bin/start-app.sh 它应该使用 3 个端点启动 api-framework,其中一个将被关闭
    • 我正在尝试运行项目 export SIMPLE_SETTINGS=magicarp.settings.flask_defaults,magicarp.settings.favicon,magicarp.settings.base 然后 ./bin/start-app.sh 出现错误无效设置文件请告诉我我做错了什么
    • 我刚刚更新了magicarp,如果你做git pull的话。您应该能够在没有任何其他设置或任何东西的情况下启动服务器。只需运行脚本。
    • 我尝试了 SIMPLE_SETTINGS=magicarp.settings.base 然后 ./bin/start-app.sh 收到此错误引发 RuntimeError('Settings are not configured') RuntimeError: Settings are not configured 用法:flask run [OPTIONS] 错误:“--port”/“-p”的值无效:不是有效的整数有任何线索吗??
    猜你喜欢
    • 2019-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多