python - Flask test_client() doesn't have request.authorization with pytest

flask test_client headers
flask test client post json
flaskr
flask-restful testing
python flask code coverage
flask mock
integration testing python flask
flaskclient

I have problem when testing my flask app with pytest. App is required basic auth which is parameters of request.authorization in flask. But with pytest, flask.test_client() doesn't have request.authorization.

Here's a code of fixture:

@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()

Here's a code of test:

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

When I run this test, I got this error:

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

Not only auth failure, but also request.authorization doesn't have any value(None). Why this happen? Is there any solution?

Thanks.

The credentials for HTTP Basic authentication must have a username and a password separated by a colon. If you're still using python 2, try this:

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

Python 3 is a little stricter about data sanity, so you have to make sure that the bytes are properly decoded before sending them to the server:

def test_index(test_client):
    credentials = b64encode(b"test_user:test_password").decode('utf-8')
    res = test_client.get("/", headers={"Authorization": f"Basic {credentials}"})
    assert res.status_code == 200

Testing code that requires a Flask app or request context, If you want to make a request to your application, use the test_client . c = app.​test_client() response = c.get('/test/url') # test response. If you want to test code  But with pytest, flask.test_client() doesn't have request.authorization. Here's a code of fixture: @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()

I found this solution. Maybe it can help someone:

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

You just have to use the library 'requests'

test_client - flask - Python documentation, For information about unit testing head over to Testing Flask Applications. with app.test_client() as c: rv = c.get('/?vodka=42') assert request.args['vodka']  I'm baffled by this. I'm using an application factory in a Flask application and under the test configuration my routes always return 404s. However when I use Flask-Script and load the app from the

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

This works for me on both python 3.6 and 2.7 whereas the following only works for me on 2.7:

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

Flask-Testing, git clone https://github.com/jarus/flask-testing.git cd flask-testing python setup.py only supports Python 2.x and therefore cannot be used with Python 3 or above. in test configuration return create_app(self) def setUp(self): db.create_all() def​  Flask provides a test client that simulates requests to the application and returns the response data. You should test as much of your code as possible. Code in functions only runs when the function is called, and code in branches, such as if blocks, only runs when the condition is met.

If you are using new version of python (in my case 3.7) you should decode base64 string. It returns bytes and after stringify it looks like b'basestring' which is not correct.

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

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

So, now my tests look like

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)}

Testing Flask Applications, Flask provides a way to test your application by exposing the Werkzeug test we will use the unittest package that comes pre-installed with Python. The code in the setUp() method creates a new test client and initializes a new database. What it does is disable the error catching during request handling so that you get​  It doesn’t work for me, but I’ve decided that I have exceeded my life-quota of debugging python-module-loading issues, so I invoke it with python -m pytest and add -s to see stuff logged to the console.

Here is how I have wrote unit tests for API's that require authentication with custom token.

###### 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"

Testing a Flask Application using pytest – Patrick's Software Blog, After reading Brian Okken's book titled “Python Testing with pytest“, I was Fixtures allow you greater flexibility than Setup()/Teadown() as you  Starting with Flask 0.8 we provide a so called “session transaction” which simulates the appropriate calls to open a session in the context of the test client and to modify it. At the end of the transaction the session is stored and ready to be used by the test client.

How to Test a Flask Application, The blog post describes how to test your Flask application. New code, everything that might break or does not work correctly should be tested. unittest is the built-in testing module for implementing unit tests in Python, it is an xUnit framework and shares some important self.app = app.test_client(). The premise of this solution is to create a wrapper class for the Flask app and override the call method to automatically set the environment variables. This way, the variables are set for all calls. This way, the variables are set for all calls.

Python Web Applications With Flask – Part III – Real Python, TestConfiguration') return app def setUp(self): db.create_all() def tearDown(self): db.session.remove() db.drop_all(). This test case doesn't do anything  Flask (source code) is a Python web framework built with a small core and easy-to-extend philosophy.. Why is Flask a good web framework choice? Flask is considered more Pythonic than the Django web framework because in common situations the equivalent Flask web application is more explicit.

Build and Test a Mini Flask Application - Better Programming, Get started with Flask and Python. Qiang Hao. Follow response = make_response('The page named %s does not exist.' \ unittest.main(). Welcome to Flask¶ Welcome to Flask’s documentation. Get started with Installation and then get an overview with the Quickstart. There is also a more detailed Tutorial that shows how to create a small but complete application with Flask. Common patterns are described in the Patterns for Flask section.

Comments
  • Hi, thanks. Now it works fine and I can see request.authorization with username and password.