Python flask jwt extended:测试期间假授权标题(pytest)

Python flask jwt extended:测试期间假授权标题(pytest),python,flask,pytest,flask-jwt,flask-jwt-extended,Python,Flask,Pytest,Flask Jwt,Flask Jwt Extended,这是我想测试的功能 @jwt_required def get_all_projects(self): # implementation not included here 我从pytest类调用该函数 def test_get_all_projects(db_session): all_projects = ProjectController.get_all_projects() 使用db\u会话fixture @pytest.fixture(scope='

这是我想测试的功能

@jwt_required
    def get_all_projects(self):
        # implementation not included here
我从pytest类调用该函数

def test_get_all_projects(db_session):
    all_projects = ProjectController.get_all_projects()
使用
db\u会话
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()
这导致了错误

>           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
手动调用
create\u access\u令牌
当我在上面的fixture中调用
create\u access\u token
时,仍然会得到相同的结果

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

yield session

如何在使用
pytest
进行测试期间伪造JWT令牌?

@JWT\u required
仅在烧瓶请求的上下文中有效。您可以使用flask测试客户端和headers name选项发送访问令牌:

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
或者,您可以使用
\uuuuuuuuuuuuuuuuuuu
属性来展开装饰过的方法。在您的情况下,它看起来像:

method_response = get_all_projects.__wrapped__()

请注意,对端点中flask jwt扩展助手函数的任何调用(如
获取jwt\u identity()
当前用户
等)。不会以这种方式工作,因为它们需要一个烧瓶请求上下文。您可以通过模拟函数内部使用的flask jwt扩展函数来解决这个问题,但随着应用程序的增长和变化,这可能会变得更难维护。

以下是我最终要做的事情,并对我有用。在conftest.py中:

@pytest.yield_fixture(scope='function')
def app():
  _app = create_app(TestConfig)
  ctx = _app.test_request_context()
  ctx.push()

  yield _app

  ctx.pop()

@pytest.fixture(scope='function')
def testapp(app):
    """A Webtest app."""
    testapp = TestApp(app)

    with testapp.app.test_request_context():
        access_token = create_access_token(identity=User.query.filter_by(email='test@test.com').first(), expires_delta=False, fresh=True)
    testapp.authorization = ('Bearer', access_token)

    return testapp
然后在TestConfig中,为flask jwt extended设置以下标志:

JWT_HEADER_TYPE = 'Bearer'
JWT_BLACKLIST_ENABLED = False

在我的例子中,我使用了
@jwt.user\u claims\u loader
包装器作为管理员角色。我还在生产方面使用cookies。为了利用用户\u声明\u加载程序,我创建了如下测试:

# conftest.py
from my.app import create_app

@pytest.fixture
def app():
    app = create_app(testing=True)
    app.config['JWT_COOKIE_CSRF_PROTECT'] = False
    app.config['JWT_TOKEN_LOCATION'] = 'json'
    jwt = JWTManager(app)

    add_user_claims_loader(jwt)

    return app
如您所见,我还将我的
JWT_TOKEN_位置
重置为
json
,这样它就不会查找cookie。我创建了另一个fixture来创建访问令牌,以便在测试中使用它

# conftest.py
@pytest.fixture
def admin_json_access_token(app, client):
    access_token = create_access_token({'username': 'testadmin',
                                        'role': 'admin'})
    return {
        'access_token': access_token
    }
我在测试中使用了它:

# test_user.py
def test_get_users(app, client, db, admin_json_access_token):
    rep = client.get('/api/v1/users', json=admin_json_access_token)
    assert rep.status_code == 200
作为我的资源的示例:

# my/resources/admin/api.py
class Users(Resource):
    @jwt_required
    @admin_required # custom wrapper that checks the claims
    def get(self):
        all_users = User.query.all()
        return all_users, 200

在单元测试期间伪造JWT令牌的一个选项是根据需要修补JWT_。更具体地说,修补基础函数
在\u请求中验证\u jwt\u
。这模拟了decorator并消除了为测试创建授权令牌的需要

from unittest.mock import patch


@patch('flask_jwt_extended.view_decorators.verify_jwt_in_request')
def test_get_all_projects(mock_jwt_required):
    # ...

旧主题,但这里有一些关于如何使用@jwt_测试函数的额外见解:

@pytest.fixture(scope="function", autouse=True)
def no_jwt(monkeypatch):
  """Monkeypatch the JWT verification functions for tests"""
  monkeypatch.setattr("flask_jwt_extended.verify_jwt_in_request", lambda: print("Verify"))

这是最好的答案,因为它回答了潜在的问题。此外,在请求资源时,我必须添加带有伪令牌的承载头。