简体   繁体   English

如何将集成测试应用于 Flask RESTful API

[英]How to apply integration tests to a Flask RESTful API

[As per https://stackoverflow.com/a/46369945/1021819 , the title should refer to integration tests rather than unit tests] [根据https://stackoverflow.com/a/46369945/1021819 ,标题应该指的是集成测试而不是单元测试]

Suppose I'd like to test the following Flask API (from here ):假设我想测试以下 Flask API(来自此处):

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)

Having saved this as flaskapi.py and run it, in the same directory I run the script test_flaskapi.py :将其保存为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()

Both the tests pass, but for the second test (defined in the TestFlaskApi ) class I haven't yet figured out how to assert that the JSON response is as expected (namely, {'hello': 'world'} ).两个测试都通过了,但是对于第二个测试(在TestFlaskApi定义)类,我还没有弄清楚如何断言 JSON 响应符合预期(即{'hello': 'world'} )。 This is because it is an instance of flask.wrappers.Response (which is probably essentially a Werkzeug Response object (cf. http://werkzeug.pocoo.org/docs/0.11/wrappers/ )), and I haven't been able to find an equivalent of the json() method for requests Response object.这是因为它是flask.wrappers.Response一个实例(它可能本质上是一个 Werkzeug Response 对象(参见http://werkzeug.pocoo.org/docs/0.11/wrappers/ )),我还没有能够为requests Response对象找到等效的json()方法。

How can I make assertions on the JSON content of the second response ?如何对第二个response的 JSON 内容进行断言?

Flask provides a test_client you can use in your tests: 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 烧瓶测试文档

I've found that I can get the JSON data by applying json.loads() to the output of the get_data() method:我发现我可以通过将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()

Both tests pass as desired:两项测试均按预期通过:

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

OK
[Finished in 0.3s]

What you're doing there is not unit testing.你在那里做的不是单元测试。 In every case, when using the requests library or the flask client, you're doing integration testing as you make actual http calls to the endpoints and test the interaction.在每种情况下,在使用请求库或 Flask 客户端时,您都是在对端点进行实际 http 调用并测试交互时进行集成测试

Either the title of the question or the approach is not accurate.问题的标题或方法都不准确。

With Python3, I got the error TypeError: the JSON object must be str, not bytes .使用 Python3,我收到错误TypeError: the JSON object must be str, not bytes It is required to decode:需要解码:

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

This question gives an explanation. 这个问题给出了解释。

The response object from test_client has a get_json method.来自test_clientresponse对象有一个get_json方法。

There's no need for converting the response to json with json.loads .无需使用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"},
        )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM