【问题标题】:How to apply integration tests to a Flask RESTful API如何将集成测试应用于 Flask RESTful API
【发布时间】:2017-06-02 18:28:45
【问题描述】:

[根据https://stackoverflow.com/a/46369945/1021819,标题应指集成测试而不是单元测试]

假设我想测试以下 Flask API(来自here):

import flask
import flask_restful

app = flask.Flask(__name__)
api = flask_restful.Api(app)

class HelloWorld(flask_restful.Resource):
    def get(self):
        return {'hello': 'world'}

api.add_resource(HelloWorld, '/')

if __name__ == "__main__":
    app.run(debug=True)

将其保存为flaskapi.py 并运行它,在同一目录中我运行脚本test_flaskapi.py

import unittest
import flaskapi
import requests

class TestFlaskApiUsingRequests(unittest.TestCase):
    def test_hello_world(self):
        response = requests.get('http://localhost:5000')
        self.assertEqual(response.json(), {'hello': 'world'})


class TestFlaskApi(unittest.TestCase):
    def setUp(self):
        self.app = flaskapi.app.test_client()

    def test_hello_world(self):
        response = self.app.get('/')

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

两个测试都通过了,但是对于第二个测试(在TestFlaskApi 中定义)类,我还没有弄清楚如何断言 JSON 响应符合预期(即{'hello': 'world'})。这是因为它是 flask.wrappers.Response 的一个实例(它可能本质上是一个 Werkzeug 响应对象(参见 http://werkzeug.pocoo.org/docs/0.11/wrappers/)),我还没有找到与 json() 方法等效的 requests Response 对象。

如何对第二个response 的 JSON 内容进行断言?

【问题讨论】:

  • 功能测试怎么样,您不希望单独运行服务以在单独的进程中运行测试吗?你将如何模拟数据库,我认为这应该是通过将对象直接传递给烧瓶来模拟请求的功能测试。

标签: python flask integration-testing flask-restful werkzeug


【解决方案1】:

Flask 提供了一个你可以在测试中使用的 test_client:

from source.api import app
from unittest import TestCase

class TestIntegrations(TestCase):
    def setUp(self):
        self.app = app.test_client()

    def test_thing(self):
        response = self.app.get('/')
        assert <make your assertion here>

Flask Testing Docs

【讨论】:

【解决方案2】:

我发现可以通过将json.loads() 应用于get_data() 方法的输出来获取JSON 数据:

import unittest
import flaskapi
import requests
import json
import sys

class TestFlaskApiUsingRequests(unittest.TestCase):
    def test_hello_world(self):
        response = requests.get('http://localhost:5000')
        self.assertEqual(response.json(), {'hello': 'world'})


class TestFlaskApi(unittest.TestCase):
    def setUp(self):
        self.app = flaskapi.app.test_client()

    def test_hello_world(self):
        response = self.app.get('/')
        self.assertEqual(
            json.loads(response.get_data().decode(sys.getdefaultencoding())), 
            {'hello': 'world'}
        )


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

两个测试都按要求通过:

..
----------------------------------------------------------------------
Ran 2 tests in 0.019s

OK
[Finished in 0.3s]

【讨论】:

  • "状态:Flask API 当前未在积极开发中。"来自github.com/flask-api/flask-api
  • @TheGrimmScientist OP 使用的是 flask-restful,而不是 flask-api
【解决方案3】:

你在那里做的不是单元测试。在任何情况下,当使用 requests 库或烧瓶客户端时,您都在做integration testing,因为您对端点进行实际的 http 调用并测试交互。

问题的标题或方法不准确。

【讨论】:

    【解决方案4】:

    使用 Python3,我收到错误 TypeError: the JSON object must be str, not bytes。需要解码:

    # in TestFlaskApi.test_hello_world
    self.assertEqual(json.loads(response.get_data().decode()), {'hello': 'world'})
    

    This question给出解释。

    【讨论】:

      【解决方案5】:

      来自test_clientresponse 对象有一个get_json 方法。

      无需使用json.loads 将响应转换为json。

      class TestFlaskApi(unittest.TestCase):
          def setUp(self):
              self.app = flaskapi.app.test_client()
      
          def test_hello_world(self):
              response = self.app.get("/")
              self.assertEqual(
                  response.get_json(),
                  {"hello": "world"},
              )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-06-07
        • 2015-05-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多