0

我创建了一个简单的烧瓶应用程序,它需要使用令牌持有者身份验证调用一些端点。不透明令牌使用 flask_of_oil OAuthFilter 装饰器和正确的客户端和秘密组合进行验证。这按预期工作,并使用 @oauth.protect() 装饰器正确验证所有请求的令牌。但是,在运行单元测试时,我需要禁用身份验证例程。

在导入模块之前,我尝试在文件顶部使用类似 unittest.mock.patch 的东西将 oauth.protect 装饰器覆盖为虚拟 lambda。

有没有办法保留 app.py 的所有功能并在测试范围内“删除”@oauth.protect()?除了简单的脚本之外,我对使用 Python 进行任何操作都很陌生,所以我有点不知所措,任何指针都将不胜感激。

以下是工作应用程序和我的基本单元测试设置的简化示例:

应用程序.py:

from flask import Flask
from flask_restx import Api, Resource
from flask_of_oil.oauth_filter import OAuthFilter

# consts
OAUTH_HOST = "https://check.my.token/oauth2/introspect"
OAUTH_CLIENT = "client"
OAUTH_SECRET = "--secret--"

app = Flask(__name__)
api = Api(app=app)
oauth = OAuthFilter(verify_ssl=True)
namespace = api.namespace('api', description='AI & ML tools')


@namespace.route('/foo')
class Foo(Resource):
    @oauth.protect()  # decorator in question
    @api.response(200, 'Success')
    @api.response(401, 'Unauthorized')
    @api.response(500, 'Unexpected Error')
    def get(self):
        return {'bar': 'foo'}


if __name__ == '__main__':
    oauth.configure_with_opaque(OAUTH_HOST, OAUTH_CLIENT, OAUTH_SECRET)
    app.run()

test_foo.py:

from unittest.mock import patch
patch('main.app.oauth.protect', lambda x: x).start()

import pytest    
from main.app import app

@pytest.fixture
def client():
    with app.test_client() as client:
        yield client

def test_foo(client):
    response = client.get(path="/api/foo", follow_redirects=True)
    assert response.status_code == 200  # ==401
4

1 回答 1

0

好的,所以我想出了一个解决方案,方法是使用更复杂的传递装饰器并直接模拟 flask_of_oil.OAuthFilter.protect 而不是在我的应用程序中使用和导入的那个。归功于单元测试中的模拟身份验证装饰器,这让我走上了正确的轨道。

from functools import wraps
from unittest.mock import patch
import pytest

def mock_auth(_):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            return f(*args, **kwargs)
        return decorated_function
    return decorator


patch('flask_of_oil.OAuthFilter.protect', mock_auth).start()

from main.app import app

@pytest.fixture
def client():
    with app.test_client() as client:
        yield client

def test_foo(client):
    response = client.get(path="/api/foo", follow_redirects=True)
    assert response.status_code == 200  # passes now
于 2021-10-05T12:21:53.253 回答