La prueba de unidades te permite verificar la calidad del código después de escribirlo. También puedes usarla para mejorar el proceso de desarrollo a medida que avanzas. En lugar de escribir pruebas luego de desarrollar tu aplicación, considera escribirlas conforme avanzas. Esto te ayuda a diseñar unidades de código pequeñas que se pueden mantener y volver a usar. También te facilita probar el código con rapidez y profundidad.
Cuando realices la prueba de unidades local, ejecuta las pruebas que están dentro de tu propio entorno de desarrollo sin involucrar componentes remotos. App Engine proporciona utilidades de prueba que usan implementaciones locales de Datastore y otros servicios de App Engine. Esto significa que puedes usar el código de estos servicios de manera local, sin implementarlo en App Engine, mediante el uso de stubs de servicio.
Un stub de servicio es un método que simula el comportamiento de un servicio. Por ejemplo, el stub de servicio de Datastore que se muestra en Escribe pruebas de Datastore y Memcache te permite probar el código de Datastore sin enviar solicitudes al real. Cualquier entidad almacenada durante una prueba de unidades de Datastore se aloja en la memoria, no en Datastore, y se borra después de ejecutar la prueba. Puedes ejecutar pruebas pequeñas y rápidas sin depender del almacén de datos.
En este documento, se detalla cómo escribir pruebas de unidades en varios servicios de App Engine y se proporciona información sobre cómo configurar un marco de trabajo de pruebas.
Presentación de las utilidades de prueba para Python 2
Un módulo de Python en App Engine denominado testbed
permite que los stubs de servicio estén disponibles para las pruebas de unidades.
Los stubs de servicio están disponibles para los siguientes servicios:
- Identidad de la app
init_app_identity_stub
- Blobstore (usa
init_blobstore_stub
) - Capacidad (usa
init_capability_stub
) - Datastore (usa
init_datastore_v3_stub
) - Archivos (usa
init_files_stub
) - Imágenes (solo para dev_appserver; usa
init_images_stub
) - LogService (usa
init_logservice_stub
) - Correo electrónico (usa
init_mail_stub
) - Memcache (usa
init_memcache_stub
) - Lista de tareas en cola (usa
init_taskqueue_stub
) - Recuperación de URL (usa
init_urlfetch_stub
) - Servicio de usuarios (usa
init_user_stub
)
Para inicializar todos los stubs al mismo tiempo, puedes usar init_all_stubs
.
Cómo escribir pruebas de Datastore y Memcache
En esta sección, se muestra un ejemplo de cómo escribir un código que pruebe el uso de los servicios de datastore y memcache.
Asegúrate de que tu ejecutor de pruebas tenga las bibliotecas adecuadas en la ruta de carga de Python, entre ellas, las bibliotecas de App Engine, yaml
(que se incluyen en el SDK de App Engine), la raíz de la aplicación y cualquier otra modificación en la ruta de acceso de la biblioteca que el código de la aplicación espera (como un directorio ./lib
local, si tienes uno). Por ejemplo:
import sys
sys.path.insert(1, 'google-cloud-sdk/platform/google_appengine')
sys.path.insert(1, 'google-cloud-sdk/platform/google_appengine/lib/yaml/lib')
sys.path.insert(1, 'myapp/lib')
Importa el módulo unittest
de Python y los módulos de App Engine pertinentes a los servicios que se prueban, en este caso memcache
y ndb
, que usan Datastore y Memcache. También importa el módulo testbed
.
Luego, crea una clase TestModel
. En este ejemplo, una función verifica si se almacenó una entidad en Memcache. Si no se encontró ninguna entidad, se verifica que haya una en Datastore. A menudo, esto puede ser redundante en la realidad, ya que ndb
usa Memcache en segundo plano, pero sigue siendo un patrón aceptable para una prueba.
A continuación, crea un caso de prueba. No importa qué servicios estén en prueba, el caso de prueba debe crear una instancia Testbed
y activarla. También debe inicializar los stubs de servicio pertinentes mediante init_datastore_v3_stub
y init_memcache_stub
. Los métodos cuyo propósito es inicializar otros stubs de servicio de App Engine se muestran en Presentación de las utilidades de pruebas para Python.
El método init_datastore_v3_stub()
sin argumentos usa un almacén de datos en la memoria que al principio está vacío. Si quieres probar una entidad de almacén de datos existente, incluye su nombre de ruta como argumento para init_datastore_v3_stub()
.
Además de setUp()
, incluye un método tearDown()
que desactive testbed. Esto restablece los stubs originales para que las pruebas no interfieran entre sí.
Luego, implementa las pruebas.
Ahora puedes usar TestModel
para escribir pruebas que usen los stubs de servicio de Datastore o Memcache en lugar de usar los servicios reales.
Por ejemplo, el método que se muestra a continuación crea dos entidades: la primera entidad usa el valor predeterminado para el atributo number
(42) y la segunda, un valor no predeterminado para number
(17). El método compila una consulta para entidades de TestModel
, pero solo en el caso de las que tienen el valor predeterminado de number
.
Después de recuperar todas las entidades que coinciden, el método prueba que se encontró exactamente una entidad y que el valor del atributo number
de esa entidad es el predeterminado.
Otro ejemplo es el siguiente método en el que se crea una entidad y se la recupera mediante la función GetEntityViaMemcache()
que creamos antes. El método prueba que se mostró una entidad y que su valor de number
es el mismo que el de la entidad antes creada.
Y, por último, invoca unittest.main()
.
Para ejecutar las pruebas, consulta Cómo ejecutar pruebas.
Cómo escribir pruebas de Cloud Datastore
Si tu app usa Cloud Datastore, recomendamos escribir pruebas que verifiquen el comportamiento de tu aplicación ante una coherencia eventual.
db.testbed
expone las opciones que facilitan este proceso:
La clase PseudoRandomHRConsistencyPolicy
te permite controlar la probabilidad de que se aplique una escritura antes de cada consulta global (no una principal). Mediante la configuración de la probabilidad en un 0%, se le indica al stub del almacenamiento de datos que opere con la cantidad máxima de coherencia eventual. La coherencia eventual máxima significa que las operaciones de escritura se confirmarán, pero su aplicación siempre fallará. Por lo tanto, las consultas globales (no la principal) no verán los cambios constantemente. Por supuesto, esto no representa la cantidad de coherencia eventual que verá tu aplicación cuando se ejecute en producción, pero configurar el almacén de datos local con el fin de que siempre se comporte de esta manera es muy útil para realizar pruebas. Si usas una probabilidad distinta de cero, PseudoRandomHRConsistencyPolicy
realiza una secuencia determinista de decisiones de coherencia para que los resultados de la prueba sean coherentes:
Las API de pruebas son útiles para verificar que tu aplicación se comporte de manera correcta en el caso de una coherencia eventual, pero ten en cuenta que el modelo de coherencia de lectura de alta replicación local es una aproximación del modelo de coherencia de lectura de alta replicación de producción, no una réplica exacta. En el entorno local, realizar get()
de una Entity
que pertenece a un grupo de entidades con una operación de escritura sin aplicar siempre hará que se vean los resultados de esta operación para las consultas globales posteriores. En producción, este no el caso.
Cómo escribir pruebas de correo electrónico
Para probar el servicio de correo electrónico, puedes usar el stub de este servicio. Al igual que con otros servicios que testbed admite, primero inicializa el stub, luego invoca el código que usa la API de correo electrónico y, por último, realiza una prueba para ver si se enviaron los mensajes correctos.
Escribe pruebas de lista de tareas en cola
Para escribir pruebas que usen el servicio de taskqueue, puedes usar el stub de taskqueue. Al igual que con otros servicios que testbed admite, primero inicializa el stub, luego invoca el código que usa la API de taskqueue y, por último, realiza una prueba para ver si se agregaron correctamente las tareas a la cola.
Configura el archivo de configuración queue.yaml
Si deseas ejecutar pruebas en un código que interactúe con una cola no predeterminada, deberás crear y especificar un archivo queue.yaml
para que use la aplicación.
A continuación, se muestra un queue.yaml
de ejemplo:
Para obtener más información sobre las opciones de queue.yaml disponibles, consulta la configuración de lista de tareas en cola.
La ubicación del archivo queue.yaml
se especifica cuando inicializas el stub:
self.testbed.init_taskqueue_stub(root_path='.')
En la muestra, queue.yaml
está en el mismo directorio que las pruebas. Si estuviera en otra carpeta, la ruta de acceso tendría que especificarse en root_path
.
Filtra tareas
get_filtered_tasks
del stub de taskqueue te permite filtrar las tareas en cola.
Esto facilita escribir pruebas que deben verificar el código que agrega varias tareas a la cola.
Escribe pruebas de tareas diferidas
Si el código de la aplicación usa la biblioteca diferida, puedes usar el stub de taskqueue junto con deferred
para verificar que las funciones diferidas se agreguen a la cola y se ejecuten de forma correcta.
Cambia las variables de entorno predeterminadas
Los servicios de App Engine suelen depender de las variables de entorno. El método activate()
de clase testbed.Testbed
usa valores predeterminados para estas, pero puedes establecer valores personalizados basados en tus necesidades de prueba con el método setup_env
de clase testbed.Testbed
.
Por ejemplo, supongamos que tienes una prueba que almacena varias entidades en Datastore, todas ellas están vinculadas al mismo ID de aplicación. Ahora, deseas volver a ejecutar las mismas pruebas, pero con un ID de aplicación diferente al que está vinculado a las entidades almacenadas. Para hacerlo, pasa el valor nuevo a self.setup_env()
como app_id
.
Por ejemplo:
Simula el acceso
Otro uso frecuente de setup_env
es simular el acceso de un usuario, con o sin privilegios de administrador, para verificar si los controladores operan de forma correcta en cada caso.
Ahora, tus métodos de prueba pueden llamar, por ejemplo, a self.loginUser('', '')
para simular que ningún usuario accedió, a self.loginUser('test@example.com', '123')
a fin de simular que un usuario no administrador accedió y a self.loginUser('test@example.com',
'123', is_admin=True)
para simular que un usuario administrador accedió.
Configura un framework de pruebas
Las utilidades de prueba del SDK no están vinculadas a un marco de trabajo específico. Puedes ejecutar las pruebas de unidades con cualquier ejecutor de pruebas disponible de App Engine, por ejemplo, nose-gae o ferrisnose. También puedes escribir tu propio ejecutor de pruebas o usar el que se muestra a continuación.
Las secuencias de comandos siguientes usan el módulo unittest de Python.
Puedes nombrar la secuencia de comandos como desees. Cuando la ejecutes, proporciona la ruta a la instalación de Google Cloud CLI o el SDK de Google App Engine y la ruta a los módulos de prueba. La secuencia de comandos descubrirá todas las pruebas en la ruta proporcionada y mostrará los resultados en la transmisión de errores estándar. Los archivos de prueba siguen la convención de tener el prefijo test
en su nombre.
Ejecuta las pruebas
Puedes realizar estas pruebas con solo ejecutar la secuencia de comandos runner.py
, que se describe en detalle en Configura un framework de pruebas:
python runner.py <path-to-appengine-or-gcloud-SDK> .