python - Flask test_client()没有使用pytest的request.authorization

时间:2015-05-14 23:23:46

标签: python-2.7 unit-testing flask pytest werkzeug

用pytest测试我的烧瓶应用程序时遇到问题 App是基本的auth,它是烧瓶中request.authorization的参数 但是使用pytest,flask.test_client()没有request.authorization

这是一个灯具代码:

@pytest.yield_fixture(scope='session')
def app()
    app = create_app()

    # some setup code

    ctx = app.app_context()
    ctx.push()
    yield app
    ctx.pop()
    # some teadown code

@pytest.fixture
def test_client(app)
     return app.test_client()

这是一个测试代码:

def test_index(test_client):
    res = test_client.get("/", headers={"Authorization": "Basic {user}".format(user=b64encode(b"test_user"))})
    assert res.status_code == 200

当我运行此测试时,我收到此错误:

E       assert 401 == 200
E        +  where 401 = <Response streamed [401 UNAUTHORIZED]>.status_code

不仅auth失败,而且request.authorization没有任何值(None) 为什么会这样?有没有解决方案?

感谢。

5 个答案:

答案 0 :(得分:11)

HTTP Basic身份验证的凭据必须具有用冒号分隔的用户名和密码。试试这个:

def test_index(test_client):
    res = test_client.get("/", headers={"Authorization": "Basic {user}".format(user=b64encode(b"test_user:test_password"))})
    assert res.status_code == 200

答案 1 :(得分:4)

我找到了这个解决方案。也许它可以帮助别人:

from requests.auth import _basic_auth_str
headers = {
   'Authorization': _basic_auth_str(username, password),
}

您只需使用库“请求”

答案 2 :(得分:1)

from requests.auth import _basic_auth_str
headers = {
   'Authorization': _basic_auth_str(username, password)
}

这在python 3.6和2.7上都对我有效,而以下内容仅在2.7上对我有效:

res = test_client.get("/", headers={"Authorization": "Basic {user}".format(user=b64encode(b"test_user:test_password"))})

答案 3 :(得分:1)

如果您正在使用新版本的python(在我的情况下为3.7),则应解码base64字符串。它返回字节,并在字符串化后看起来像 b'basestring'不正确。

>>> base64.b64encode(b"user:password")
b'dXNlcjpwYXNzd29yZA=='

>>> base64.b64encode(b"user:password").decode()
'dXNlcjpwYXNzd29yZA=='

所以,现在我的测试看起来像

class TestServer(unittest.TestCase):

    def setUp(self) -> None:
        self.client = app.test_client()
        user_credentials = base64.b64encode(b"user:password").decode()
        self.headers = {"Authorization": "Basic {}".format(user_credentials)}

答案 4 :(得分:0)

这是我为需要使用自定义令牌进行身份验证的API编写单元测试的方式。

###### In your conftest.py file have the below methods

from connexion import FlaskApp

logging.basicConfig(level=logging.DEBUG)

API_FOLDER = pathlib.Path(__file__).parent / '..'


@pytest.fixture(scope="session")
def insecure_client():  # This is used for route tests that DO NOT require authorization.
    cxn_app = FlaskApp(__name__,
                       port=5001,
                       specification_dir=API_FOLDER,
                       debug=True,
                       options={"debug": True, "swagger_ui": False})

    cxn_app.add_api('your_api.yaml', resolver=RestyPlusResolver('api.routes'))
    cxn_app._spec_file = 'your_api.yaml'
    # connection stores the Flask app at app
    cxn_app.app.config['SOME_KEY'] = config.CONFIG['SOME_KEY']
    flask_jwt.JWT(cxn_app.app, None, None)
    flask_cors.CORS(cxn_app.app)
    cxn_app.app.app_context()
    return cxn_app.app.test_client()


@pytest.fixture(scope="session")
def secure_client():  # This is used for route tests that REQUIRE authorization.
    cxn_app = FlaskApp(__name__,
                       port=5001,
                       specification_dir=API_FOLDER,
                       debug=True,
                       options={"debug": True, "swagger_ui": False})

    cxn_app.add_api('open_api.yaml', resolver=RestyPlusResolver('api.routes'))
    cxn_app._spec_file = 'openapi.yaml'
    # connection stores the Flask app at app
    cxn_app.app.config['SOME_KEY'] = config.CONFIG['SOME_KEY']
    flask_jwt.JWT(cxn_app.app, None, None)
    flask_cors.CORS(cxn_app.app)
    cxn_app.app.app_context()
    client = cxn_app.app.test_client()
    json_dict = {'user': 'your_username', 'password': 'your_pwd'}
    # call the auth to get a token which can be used for API calls that require authentication.
    # see below on how this is used in pytest of a route.
    response = client.post('/auth', data=json.dumps(json_dict), content_type='application/json')
    data = json_of_response(response)
    setattr(client, '__token', data['token'])
    return client


def post_json(client, url, json_dict):
    """Send dictionary json_dict as a json to the specified url """
    return client.post(url, data=json.dumps(json_dict), content_type='application/json')


def json_of_response(response):
    """Decode json from response"""
    return json.loads(response.data.decode('utf8'))

### Example Pytest of API that requires authentication.
def test_my_post(mocker, secure_client):
    json_dict = {'id': 'TEST_01', 'phone': 'PHONE_02'}
    mocker.patch('yourapi.services.User.create_user', return_value=("Success", 201))
    response = secure_client.post('/user', data=json.dumps(json_dict), content_type='application/json', headers={'X-Auth':secure_client.__token})
    data = json_of_response(response)
    assert response.status_code == 201
    assert data == "Success"