Python: pytest accessing Flask session and request context variables.
How to enable pytest methods to access Flask’s context variables, session and request.
Python: pytest accessing Flask session and request context variables. |
I’ve previously blogged about pytest’s application fixture and test client fixture in Python: pytest and Flask template context processor functions. ( Please see section pytest entry module conftest.py. )
The test client fixture in the mentioned post:
@pytest.fixture(scope='module')
def test_client( app ):
"""
Creates a test client.
app.test_client() is able to submit HTTP requests.
The app argument is the app() fixture above.
"""
with app.test_client() as testing_client:
yield testing_client # Return to caller.
When testing the codes that access Flask’s context variable session, the above fixture will not work. To access this variable, the official document states:
If you want to access or set a value in the session before making a request, use the client’s session_transaction() method in a with statement. It returns a session object, and will save the session once the block ends.
I tried that, and it does not work… It’s a “popular” problem. It’s been around for a few years. There are a few posts on it, however, most suggestions fail to work for me.
Sessions are empty when testing #69 raises this problem, and user russmac suggests a solution:
@pytest.fixture(scope='module')
def test_client( app ):
"""
Creates a test client.
app.test_client() is able to submit HTTP requests.
The app argument is the app() fixture above.
"""
with app.test_client() as testing_client:
"""
See: https://github.com/pytest-dev/pytest-flask/issues/69
Sessions are empty when testing #69
"""
with testing_client.session_transaction() as session:
session['Authorization'] = 'redacted'
yield testing_client # Return to caller.
This works for me. However, to access variable session my test codes must be within:
with app.test_request_context():
Or else, it raises the error RuntimeError: Working outside of request context. Also, without the above call, the codes proper would not be able to access the request variable during testing.
Following is a proper test method of a project I’m working on:
@pytest.mark.timesheet_bro
def test_close( app ):
bro_obj = TimesheetBRO( 1 )
#
# RuntimeError: Working outside of request context.
#
# session[ 'user_id' ] = 100
#
with app.test_request_context( '?searchType={}'.format(UNRESTRICT_SEARCH_TYPE) ):
assert request.args[ 'searchType' ] == UNRESTRICT_SEARCH_TYPE
assert request.values.get( 'searchType' ) == UNRESTRICT_SEARCH_TYPE
session[ 'user_id' ] = 1
data = bro_obj.close( 326 )
assert bro_obj.last_message == ''
assert data['status']['code'] == HTTPStatus.OK.value
Please note, within the codes proper, session[ ‘user_id’ ] is set after a user has successfully logged in. Setting this value in the test codes to create a correct pre-condition for the codes being tested. Please also note, request.values.get( ‘searchType’ ) is also used in the codes under testing.
Following is another proper test method which does not submit any request parameters:
@pytest.mark.timesheet_bro
def test_update_last_timesheet_id( app ):
bro_obj = TimesheetBRO( 1 )
with app.test_request_context():
session[ 'user_id' ] = 1
data = bro_obj.update_last_timesheet_id( 1, 1123 )
assert bro_obj.last_message == ''
assert data['status']['code'] == HTTPStatus.OK.value
I hope you will find this helpful at some point… And thank you for reading.