【问题标题】:Application context errors when locally testing a (Python) Google Cloud Function本地测试 (Python) Google Cloud Function 时的应用程序上下文错误
【发布时间】:2018-12-18 15:51:03
【问题描述】:

我正在尝试在本地测试我希望部署为 Google Cloud 函数的 Python 函数。这些函数似乎本质上是基于 Flask 的,我发现返回 JSON 的最好方法是使用 Flask 的 jsonify 函数。部署时这似乎工作正常,但我想设置一些本地单元测试,这就是我卡住的地方。只需添加行 import jsonify,会导致以下错误:

RuntimeError: Working outside of application context.

Stackoverflow 上有几篇似乎与此问题相关的帖子,但 Google Cloud Functions 并没有真正遵循 Flask 模式。据我所知,没有应用程序上下文,也没有装饰器。我发现的所有示例都对这个特定的用例没有用处。任何人都可以建议一种构建单元测试的方法,该方法将尊重应用程序上下文并且仍然与此处的 GCF 模式兼容。

我有一个单元测试,我可以分享它,但是当你运行以下命令时,你会看到同样的错误,方法调用在 ma​​in 内。

import os
import json
from flask import jsonify
from unittest.mock import Mock

def dummy_request(request):

    request_json = request.get_json()
    if request_json and 'document' in request_json:
        document = request_json['document']
    else:
        raise ValueError("JSON is invalid, or missing a 'docuemnt' property")

    data = document
    return jsonify(data)


if __name__ == '__main__':
    data = {"document":"This is a test document"}
    request = Mock(get_json=Mock(return_value=data), args=data)
    result = dummy_request(request)
    print(result)

【问题讨论】:

  • 我开始走这条路,因为我认为我需要 Flask jsonify 或 Response 方法来为 Google Cloud Function 生成正确的输出。我更习惯于 AWS Lambda,其中每个函数都必须生成 JSON 格式的记录代理格式。从那以后我意识到我可以简单地返回一个 JSON 字符串。至于标题和状态代码,它们可以作为元组的一部分返回,如文档中所示: return ('Hello World!', 200, headers) 所以,对我来说最简单的选择是删除所有 Flask 响应我的功能中的东西并正常测试。

标签: python flask google-cloud-platform google-cloud-functions google-contacts-api


【解决方案1】:

您真的不需要测试flask.jsonify 是否按预期工作,对吧?这是第三方功能。

您实际上要测试的是,flask.jsonify 是使用正确的数据调用的,因此您可以只修补 flask.jsonify,并断言是否调用了模拟:

import flask
from unittest.mock import Mock, patch

def dummy_request(request):

    request_json = request.get_json()
    if request_json and 'document' in request_json:
        document = request_json['document']
    else:
        raise ValueError("JSON is invalid, or missing a 'docuemnt' property")

    data = document
    return flask.jsonify(data)


@patch('flask.jsonify')
def test(mock_jsonify):
    data = {"document": "This is a test document"}
    request = Mock(get_json=Mock(return_value=data), args=data)
    dummy_request(request)
    mock_jsonify.assert_called_once_with("This is a test document")


if __name__ == '__main__':
    test()

【讨论】:

  • 谢谢。这适用于 pytest 和上面的示例。当我将 Flask 函数之外的测试函数移到 tests.py 中时,我仍然遇到了一些上下文错误。不过,我仍在努力。
  • 不确定我是否关注,但请随时提出新问题,我很乐意看看。
【解决方案2】:

I'd recommend you to take a look at Flask's documentation on how to test Flask apps,它很好地描述了如何设置测试和获取应用程序上下文。

附: jsonify 需要应用程序上下文,但 json.dumps 不需要。也许你可以使用后者?

【讨论】:

  • 是的,我查看了文档并整理了一个简单的工作示例来测试 Flask 应用程序。但是,Google Cloud Function 并不是真正 Flask 应用程序。它没有装饰器,它的方法必须接收请求对象。所以,这条路线并没有真正奏效。目前,似乎最好的选择是使用 json.dumps 简单地返回 json,如您所建议的。我不再确定我在哪里获得了 jsonify 的想法——可能是在 Stackoverflow 上的其他地方。
【解决方案3】:

我遇到了同样的问题。正如您所说,烧瓶测试似乎不太适合 Cloud Functions,我对代码的工作方式很满意,所以不想改变它。在测试的 setUp() 中添加应用程序上下文,然后将其用于所需的调用,这对我有用。像这样的...

import unittest
import main
from flask import Flask

class TestSomething(unittest.TestCase):

    def setUp(self):
        self.app = Flask(__name__)

    def test_something(self):      

        with self.app.app_context():
            (body, code) = main.request_something()

        self.assertEqual(200, code, "The request did not return a successful response")

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

【讨论】:

    猜你喜欢
    • 2020-11-02
    • 2020-01-04
    • 1970-01-01
    • 2019-05-10
    • 2017-02-12
    • 1970-01-01
    • 2018-08-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多