pythonflaskpytestfixturespytest-bdd

test is failing because flask is returning stream insted of json


I'm my flask app, I have an route/controller that creates something I call an entity:

@api.route('/entities', methods=['POST'])
def create_entity():
    label = request.get_json()['label']
    entity = entity_context.create(label)
    print('the result of creating the entity: ')
    print(entity)
    return entity

After creating an entity, the following is printed:

the result of creating the entity: 
{'label': 'Uganda', '_id': '{"$oid": "5ff5df24bb80fcf812631c53"}'}

I wrote the following test for this controller:

@given("an entity is created with label Uganda", target_fixture="create_entity")
def create_entity(test_client):
    result = test_client.post('api/entities', json={"label": "Uganda"})
    return result

@then("this entity can be read from the db")
def get_entities(create_entity, test_client):
    print('result of create entity: ')
    print(create_entity)
    response = test_client.get('api/entities').get_json()
    assert create_entity['_id'] in list(map(lambda x : x._id, response))

test client is defined in conftest.py as the following:

@pytest.fixture
def test_client():
    flask_app = init_app()
    # Create a test client using the Flask application configured for testing
    with flask_app.test_client() as flask_test_client:
        return flask_test_client

My test is failing with the following error:

create_entity = <Response streamed [200 OK]>, test_client = <FlaskClient <Flask 'api'>>

    @then("this entity can be read from the db")
    def get_entities(create_entity, test_client):
        print('result of create entity: ')
        print(create_entity)
        response = test_client.get('api/entities').get_json()
>       assert create_entity['_id'] in list(map(lambda x : x._id, response))
E       TypeError: 'Response' object is not subscriptable

the result of creating the entity: 
{'label': 'Uganda', '_id': '{"$oid": "5ff5df24bb80fcf812631c53"}'}
result of create entity: 
<Response streamed [200 OK]>.      

Apparently create_entity is not returning a simple object, but a streamed response instead:

<Response streamed [200 OK]>

I don't understand why this wouldn't return simple json, if the controller returns json?


Solution

  • your test has a few problems

    first you're not executing in the flask test context:

    @pytest.fixture
    def test_client():
        flask_app = init_app()
        # Create a test client using the Flask application configured for testing
        with flask_app.test_client() as flask_test_client:
            return flask_test_client
    

    this needs to be yield flask_test_client -- otherwise the context manager has exited by the time your test runs

    second, you're getting a Response object for create_entity because that's what your @given fixture is returning:

    @given("an entity is created with label Uganda", target_fixture="create_entity")
    def create_entity(test_client):
        result = test_client.post('api/entities', json={"label": "Uganda"})
        return result
    

    the result of .post(...) is a Response object, if you want that to be a dict of the json you'll need to call .get_json() on it