wake-up-neo.com

Anwenden von Integrationstests (anstelle von Komponententests) auf eine Flask RESTful API

[Gemäß https://stackoverflow.com/a/46369945/1021819 sollte sich der Titel eher auf Integrationstests als auf Komponententests beziehen]

Angenommen, ich möchte die folgende Flask API (von hier ) testen:

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)

Nachdem ich dies als flaskapi.py Gespeichert und ausgeführt habe, führe ich im selben Verzeichnis das Skript test_flaskapi.py Aus:

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()

Beide Tests bestehen, aber für die zweite Testklasse (definiert in der Klasse TestFlaskApi) habe ich noch nicht herausgefunden, wie die erwartete JSON-Antwort bestätigt werden kann (nämlich {'hello': 'world'}). Dies liegt daran, dass es sich um eine Instanz von flask.wrappers.Response Handelt (bei der es sich wahrscheinlich im Wesentlichen um ein Werkzeug Response-Objekt handelt (vgl. http://werkzeug.pocoo.org/docs/0.11/wrappers/ ). ), und ich konnte kein Äquivalent der json() -Methode für requestsResponse -Objekt finden.

Wie kann ich Aussagen zum JSON-Inhalt des zweiten response machen?

21
Kurt Peek

Ich habe festgestellt, dass ich die JSON-Daten durch Anwenden von json.loads() auf die Ausgabe der get_data() -Methode abrufen kann:

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()

Beide Tests bestehen wie gewünscht:

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

OK
[Finished in 0.3s]
25
Kurt Peek

Flask bietet einen test_client, den Sie in Ihren Tests verwenden können:

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

32

Was Sie dort tun, ist kein Unit-Test. In jedem Fall führen Sie bei Verwendung der Anforderungsbibliothek oder des flask client) Integrationstests tatsächliche http-Aufrufe an die Endpunkte durch und testen die Interaktion.

Entweder ist der Titel der Frage oder der Ansatz nicht korrekt.

18
Luisa Emme

Mit Python3 habe ich den Fehler TypeError: the JSON object must be str, not bytes. Es ist erforderlich zu dekodieren:

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

Diese Frage gibt eine Erklärung.

2
pylipp