Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flask-jwt-extended: Fake Authorization Header during testing (pytest)

This is the function I wish to test

@jwt_required
    def get_all_projects(self):
        # implementation not included here

I call the function from a pytest class

def test_get_all_projects(db_session):
    all_projects = ProjectController.get_all_projects()

with the db_session fixture

@pytest.fixture(scope='function')
def db_session(db, request):
    """Creates a new database session for a test."""
    engine = create_engine(
                            DefaultConfig.SQLALCHEMY_DATABASE_URI,
                            connect_args={"options": "-c timezone=utc"})
    DbSession = sessionmaker(bind=engine)
    session = DbSession()
    connection = engine.connect()
    transaction = connection.begin()
    options = dict(bind=connection, binds={})
    session = db.create_scoped_session(options=options)
    db.session = session

    yield session

    transaction.rollback()
    connection.close()
    session.remove()

This result in the error

>           raise NoAuthorizationError("Missing {} Header".format(header_name))
E           flask_jwt_extended.exceptions.NoAuthorizationError: Missing Authorization Header

../../.virtualenvs/my-app/lib/python3.6/site-packages/flask_jwt_extended/view_decorators.py:132: NoAuthorizationError

Manually Calling create_access_token

I still get the same result when I call create_access_token in the fixture above

db.session = session
session._test_access_token = create_access_token(identity='pytest')

yield session

How can I fake JWT tokens during testing with pytest?

like image 340
Hanxue Avatar asked Oct 20 '17 10:10

Hanxue


People also ask

How to perform authentication with JWT in flask?

Next try to fetch the list of users. To do that, change the endpoint to /user and then in the headers section, add a field as x-access-token and add the JWT token in the value and click on Send. You will get the list of users as JSON. So, this is how you can perform authentication with JWT in Flask.

What is flask-JWT-extended?

Flask-JWT-Extended not only adds support for using JSON Web Tokens (JWT) to Flask for protecting routes, but also many helpful (and optional) features built in to make working with JSON Web Tokens easier. These include: Automatic user loading ( current_user ).

How to get the JWT token of a user?

This token will identify us as logged in. The JSON contains the token. Note it down. Next try to fetch the list of users. To do that, change the endpoint to /user and then in the headers section, add a field as x-access-token and add the JWT token in the value and click on Send.

Can I pass arguments to pytest when testing flask applications?

Even when checking code coverage, arguments can still be passed to pytest: This article provides a guide for testing Flask applications, focusing on: Patrick is a software engineer from the San Francisco Bay Area with experience in C++, Python, and JavaScript. His favorite areas of teaching are Vue and Flask.


2 Answers

One option for faking JWT tokens during unit testing is to patch jwt_required. More specifically patch the underlying function verify_jwt_in_request. This mocks the decorator and removes the need to create authorization tokens for the test.

from unittest.mock import patch


@patch('flask_jwt_extended.view_decorators.verify_jwt_in_request')
def test_get_all_projects(mock_jwt_required):
    # ...
like image 146
smarlowucf Avatar answered Sep 20 '22 17:09

smarlowucf


@jwt_required only works in the context of a Flask request. You can send in the access token using the flask test client with the headers name option:

def test_foo():
    test_client = app.test_client()
    access_token = create_access_token('testuser')
    headers = {
        'Authorization': 'Bearer {}'.format(access_token)
    }
    response = test_client.get('/foo', headers=headers)
    # Rest of test code here

Optionally, you could unwrap the decorated method by using the __wrapped__ property. In your case, it would look like:

method_response = get_all_projects.__wrapped__()

Note that any calls to the flask-jwt-extended helper functions in your endpoint (such as get_jwt_identity(), current_user, etc). would not work this way, as they require a flask request context. You could get around this by mocking the flask-jwt-extended functions used inside the function, but that may be harder to maintain as the application grows and changes.

like image 38
vimalloc Avatar answered Sep 20 '22 17:09

vimalloc