Как применить интеграционные тесты (а не модульные тесты) к API-интерфейсу Flask RESTful

[Согласно qaru.site/info/630265/..., заголовок должен относиться к интеграционным тестам, а не к единичным тестам]

Предположим, что я хотел бы протестировать следующий API-интерфейс Flask (отсюда):

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 это как 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 Response (см. Http://werkzeug.pocoo.org/docs/0.11/wrappers/)), и я не был способный найти эквивалент метода json() для requests объекта Response.

Как я могу сделать утверждения о содержании JSON во втором response?

Ответ 1

Я обнаружил, что могу получить данные JSON, применив json.loads() к выходу метода get_data():

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]

Ответ 2

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>

Документы для проверки колб

Ответ 3

Что вы там делаете, это не модульное тестирование. В каждом случае при использовании библиотеки запросов или клиента флешки вы выполняете тестирование интеграции, когда вы делаете фактические 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'})

Этот вопрос дает объяснение.