Как включить методы pytest для доступа к контекстным переменным Flask, сессии и запросу.
Ранее я уже писал в блоге о приспособлении pytest для приложений и приспособлении для тестового клиента в Python: pytest и функциях контекстного процессора шаблона Flask. (См. раздел pytest entry module conftest.py).
Приспособление для тестового клиента в упомянутом посте:
@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.
При тестировании кодов, которые обращаются к контекстной переменной Flask session, вышеуказанное приспособление работать не будет. Для доступа к этой переменной в официальном документе говорится следующее:
Если вы хотите получить доступ или установить значение в сессии до выполнения запроса, используйте метод session_transaction() клиента в операторе with. Он возвращает объект сессии и сохранит сессию после завершения блока.
https://flask.palletsprojects.com/en/2.2.x/testing/
Я пробовал это, и это не работает… Это «популярная» проблема. Она существует уже несколько лет. Есть несколько сообщений по ней, однако большинство предложений не работают для меня.
Сессии пусты при тестировании #69 поднимает эту проблему, а пользователь russmac предлагает решение:
@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.
Это работает для меня. Однако, чтобы получить доступ к переменной сессии, мои тестовые коды должны быть внутри:
with app.test_request_context():
Иначе возникает ошибка RuntimeError: Working outside of request context. Кроме того, без вышеуказанного вызова, собственно коды не смогут получить доступ к переменной запроса во время тестирования.
Ниже приведен правильный метод тестирования проекта, над которым я работаю:
@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
Обратите внимание, что в самом коде session[ ‘user_id’ ] устанавливается после того, как пользователь успешно вошел в систему. Установите это значение в тестовых кодах, чтобы создать правильное предусловие для тестируемых кодов. Обратите внимание, что request.values.get( ‘searchType’ ) также используется в тестируемых кодах.
Ниже приведен еще один правильный метод тестирования, который не передает никаких параметров запроса:
@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
Надеюсь, что в какой-то момент это будет вам полезно… И спасибо, что прочитали.