Estoy tratando de usar pytest para probar mi aplicación Flask. Tengo el siguiente caso de prueba para un punto final que requiere información de current_user de flask_login :
def test_approval_logic(): with app.test_client() as test_client: app_url_put = '/requests/process/2222' with app.app_context(): user = User.query.filter_by(uid='xxxxxxx').first() with app.test_request_context(): login_user(user) user.authenticated = True db.session.add(user) data = dict( state='EXAMPLE_STATE_NAME', action='approve' ) resp = test_client.put(app_url_put, data=data) assert resp.status_code == 200 Dentro de test_request_context , puedo configurar current_user correctamente. Sin embargo, esta prueba falla porque en la vista de requests donde se maneja el PUT, no hay un usuario conectado y 500 resultados de error. El mensaje de error es AttributeError: 'AnonymousUserMixin' object has no attribute 'email' . ¿Alguien puede explicar por qué current_user desaparece y cómo puedo configurarlo correctamente?
Así es como lo hago en mis sitios:
user = User.query.filter_by(user_id='xxxxxxx').one_or_none() if user: user.authenticated = True db.session.add(user) db.session.commit() login_user(user) else: # here I redirect to an unauthorized page, as the user wasn't found No sé si el orden es el problema o simplemente la ausencia de db.session.commit() , pero creo que debe haber hecho ambas cosas para que su solicitud de colocación funcione.
Tenga en cuenta, también, que estoy usando one_or_none() porque no debería haber una posibilidad de múltiples usuarios con el mismo user_id , solo True o False dependiendo de si se encontró un usuario o no.
La session actual no está vinculada a test_client , por lo que la solicitud utiliza una nueva sesión.
Configure la cookie de sesión en el cliente, de modo que Flask pueda cargar la misma sesión para la solicitud:
from flask import session def set_session_cookie(client): val = app.session_interface.get_signing_serializer(app).dumps(dict(session)) client.set_cookie('localhost', app.session_cookie_name, val)Uso:
# with app.test_client() as test_client: # Change these # with app.app_context(): # # with app.test_request_context(): # with app.test_request_context(), app.test_client() as test_client: # to this login_user(user) user.authenticated = True db.session.add(user) data = dict( state='EXAMPLE_STATE_NAME', action='approve' ) set_session_cookie(test_client) # Add this resp = test_client.put(app_url_put, data=data)with app.test_request_context()with app.test_client() with app.test_client() conserva el contexto de las solicitudes (Flask doc: Keeping the Context Around ), por lo que obtendría este error al salir de un interior with app.test_request_context() :
AssertionError: apareció un contexto de solicitud incorrecto. (
<RequestContext 'http://localhost/requests/process/2222' [PUT] of app>en lugar de<RequestContext 'http://localhost/' [GET] of app>)
En su lugar, ingrese app.test_request_context() antes app.test_client() como se muestra arriba.
with app.app_context() with app.test_request_context() ya empuja un contexto de aplicación, por lo que with app.app_context() no es necesario.
De https://flask.palletsprojects.com/en/2.0.x/api/#flask.Flask.test_request_context :
Esto es principalmente útil durante las pruebas, donde es posible que desee ejecutar una función que use datos de solicitud sin enviar una solicitud completa.
Uso:
data = dict( state='EXAMPLE_STATE_NAME', action='approve' ) with app.test_request_context(data=data): # Pass data here login_user(user) user.authenticated = True db.session.add(user) requests_process(2222) # Call function for '/requests/process/2222' directlySupongo que no se pasa ninguna cookie de sesión en su solicitud PUT.
Aquí hay un ejemplo de cómo registro a un usuario durante mis pruebas (personalmente utilizo unittest en lugar de pytest , así que reduje el código al mínimo estricto, pero avíseme si desea un ejemplo completo con unittest )
from whereyourappisdefined import application from models import User from flask_login import login_user # Specific route to log an user during tests @application.route('/auto_login/<user_id>') def auto_login(user_id): user = User.query.filter(User.id == user_id).first() login_user(user) return "ok" def yourtest(): application.config['TESTING'] = True # see my side note test_client = application.test_client() response = test_client.get(f"/auto_login/1") app_url_put = '/requests/process/2222' data = dict( state='EXAMPLE_STATE_NAME', action='approve' ) r = test_client.put(app_url_put, data=data)En la documentación podemos leer: https://werkzeug.palletsprojects.com/en/2.0.x/test/#werkzeug.test.Client
El parámetro use_cookies indica si las cookies deben almacenarse y enviarse para solicitudes posteriores. Esto es True por defecto, pero pasar False deshabilitará este comportamiento.
Entonces, durante la primera solicitud GET /auto_login/1 , la aplicación recibirá una cookie de sesión y la conservará para futuras solicitudes HTTP.
Nota al margen:
Durante la configuración, se activa el indicador de configuración de PRUEBA. Lo que esto hace es deshabilitar la detección de errores durante el manejo de solicitudes para que obtenga mejores informes de errores al realizar solicitudes de prueba en la aplicación.