Connexion: What's the easiest way to implement acceptance/unit tests for generated Flask app?

Created on 16 Nov 2017  路  5Comments  路  Source: zalando/connexion

I'm currently in the process of writing acceptance tests for a connexion based API in Flask. As a Flask user i'm used to test stuff with py.test and the pip modules: pytest-flask and / or Flask_Testing

Both have helpers to provide some config and start a live server when needed. This doesn't seem to work with the Flask app created by Connexion. This also makes it nearly impossible to use Flask's config system and the url_for() methods.

Is there a way to use the testing plugins or to create a more Flask compliant app?

Possibly related to #489 and #364

question

Most helpful comment

I had a good experience using the WebTest library in the past (pip install webtest): https://docs.pylonsproject.org/projects/webtest/en/latest/
It will test your application on WSGI level which has some benefits:

  • It is independent of the underlying implementation framework - your tests will work now with connexion/Flask and keep working if you decide to go for the gevent or tornado or any other WSGI-compatible backend in the future.
  • Everything works on the WSGI-API level, no need to start a "real" webserver in the background and shut it down again after your tests.
  • The tests can be run with all usual Python unittest runners (the built-in one, py.test, nose etc.)

The documentation of WebTest is quite extensive and covers all major use cases. A quick example to get started:

from webtest import TestApp
import unittest

from main import app # the connexion Flask app object

class TestEndpoints(unittest.TestCase):
    # could also be set up globally outside of this class
    @classmethod
    def setUpClass(cls):
        cls.app = TestApp(app)

    def test_some_endpoint(self):
        response = self.app.get('/some/endpoint').json()
        expected_response = dict(foo='bar', baz='buz')
        self.assertDictEqual(response, expected_response)

All 5 comments

This is how I use it now:
I added a construction to the place where the app is inited, so that it can return a flask app when needed, something like:

def run(actually_run=True):
    app = connexion.App(__name__, specification_dir='./swagger/')
    api = app.add_api(swagger_file)
    if actually_run:
        app.run(host=HOST, port=PORT, ...)
    else:
        return app.app

Then a live server can be started from tests that need it:

import requests
from flask_testing import LiveServerTestCase
from main import run_application

class MyTest(LiveServerTestCase):

    def create_app(self):
        app = run(False)
        return app

    def test_server_is_up_and_running(self):
        response = requests.get(f"{self.get_server_url()}/an_endpoint_for_your_api")
        self.assertEqual(response.status_code, 200)

I had a good experience using the WebTest library in the past (pip install webtest): https://docs.pylonsproject.org/projects/webtest/en/latest/
It will test your application on WSGI level which has some benefits:

  • It is independent of the underlying implementation framework - your tests will work now with connexion/Flask and keep working if you decide to go for the gevent or tornado or any other WSGI-compatible backend in the future.
  • Everything works on the WSGI-API level, no need to start a "real" webserver in the background and shut it down again after your tests.
  • The tests can be run with all usual Python unittest runners (the built-in one, py.test, nose etc.)

The documentation of WebTest is quite extensive and covers all major use cases. A quick example to get started:

from webtest import TestApp
import unittest

from main import app # the connexion Flask app object

class TestEndpoints(unittest.TestCase):
    # could also be set up globally outside of this class
    @classmethod
    def setUpClass(cls):
        cls.app = TestApp(app)

    def test_some_endpoint(self):
        response = self.app.get('/some/endpoint').json()
        expected_response = dict(foo='bar', baz='buz')
        self.assertDictEqual(response, expected_response)

are there any updates on writing unit tests for controllers?

I found this repo immensely helpful for getting going with testing connexion: https://github.com/hirose31/connexion-tiny-petstore

(it also uses WebTest, as recommended by @dirkschneemann)

There may be a way to get testing working with using flask's internal test client. I have created a PR showing it as an example: #957

Let me know what you think, or if I am missing something that you are looking for.

Was this page helpful?
0 / 5 - 0 ratings