Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test a Connexion/Flask app?

I'm using the Connexion framework for Flask to build a microservice. I would like to write tests for my application using py.test.

In the pytest-flask doc it says to create a fixture in conftest.py that creates the app like so:

conftest.py

import pytest

from api.main import create_app


@pytest.fixture
def app():
    app = create_app()
    return app

In my test I'm using the client fixture like this:

test_api.py

def test_api_ping(client):
    res = client.get('/status')
    assert res.status == 200

However when I run py.test I get the following error message:

==================================== ERRORS ====================================
_______________________ ERROR at setup of test_api_ping ________________________

request = <SubRequest '_monkeypatch_response_class' for <Function 'test_api_ping'>>
monkeypatch = <_pytest.monkeypatch.MonkeyPatch instance at 0x7f9f76b76518>

    @pytest.fixture(autouse=True)
    def _monkeypatch_response_class(request, monkeypatch):
        """Set custom response class before test suite and restore the original
        after. Custom response has `json` property to easily test JSON responses::
    
            @app.route('/ping')
            def ping():
                return jsonify(ping='pong')
    
            def test_json(client):
                res = client.get(url_for('ping'))
                assert res.json == {'ping': 'pong'}
    
        """
        if 'app' not in request.fixturenames:
            return
    
        app = request.getfuncargvalue('app')
        monkeypatch.setattr(app, 'response_class',
>                           _make_test_response_class(app.response_class))
E       AttributeError: 'App' object has no attribute 'response_class'

How can I make py.test work? Here is my create_app function:

main.py

import connexion


def create_app():
    app = connexion.App(__name__, port=8002,)
    app.add_api('swagger.yaml')
    return app


if __name__ == "__main__":
    create_app().run()
like image 859
Sebastian Wozny Avatar asked Mar 21 '17 17:03

Sebastian Wozny


People also ask

How do you test an API in Flask?

Testing Flask requires that we first import a Flask instance app from our api (created in our application), as seen in the previous snippet. The imported instance then exposes a test_client() method from Flask that contains the features needed to make HTTP requests to the application under test.

How do you mock request in Flask?

Here's an example below. import pytest from app import create_app @pytest. fixture def request_context(): """create the app and return the request context as a fixture so that this process does not need to be repeated in each test """ app = create_app('module.

What is Flask Connexion?

Connexion is a framework on top of Flask that automagically handles HTTP requests defined using OpenAPI (formerly known as Swagger), supporting both v2. 0 and v3. 0 of the specification. Connexion allows you to write these specifications, then maps the endpoints to your Python functions.


2 Answers

Using fixtures

test_api.py

import pytest import connexion  flask_app = connexion.FlaskApp(__name__) flask_app.add_api('swagger.yml')   @pytest.fixture(scope='module') def client():     with flask_app.app.test_client() as c:         yield c   def test_health(client):     response = client.get('/health')     assert response.status_code == 200 

swagger.yml

swagger: '2.0' info:   title: My API   version: '1.0' consumes:   - application/json produces:   - application/json schemes:   - https paths:   /health:     get:       tags: [Health]       operationId: api.health       summary: Health Check       responses:         '200':           description: Status message from server describing current health 

api.py

def health():     return {'msg': 'ok'}, 200 

Using Swagger Tester

Another solution using swagger-tester:

test_api.py

from swagger_tester import swagger_test  authorize_error = {     'get': {         '/health': [200],     } }  def test_swagger():     swagger_test('swagger.yml', authorize_error=authorize_error) 

Cool thing about this library is that you can use the examples provided in your spec. But I don't think it works out of the box with connexion.RestyResolver: you'll have to specify the OperationId at each endpoint.

like image 106
Kamil Sindi Avatar answered Nov 01 '22 09:11

Kamil Sindi


import pytest from json import JSONEncoder import pytest from connexion import App  SWAGGER_PATH = "path_to_directory_that_containes_swagger_file"  @pytest.fixture def app():     app = App(__name__, specification_dir=SWAGGER_PATH)     app.app.json_encoder = JSONEncoder     app.add_api("swagger.yaml")     app_client = app.app.test_client()     return app_client   def test_health(app) -> None:     """     :except: success     """     response = app.get("/health", content_type='application/json')     assert response.status_code == 200 

For more info check this.

like image 32
Shirantha Madusanka Avatar answered Nov 01 '22 09:11

Shirantha Madusanka