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 de Datastore.
En este documento se detalla cómo configurar un marco de trabajo de pruebas y cómo escribir pruebas de unidades en los servicios locales de App Engine.
Configura un marco de trabajo de pruebas
Aunque las utilidades de prueba del SDK no están vinculadas a un marco de trabajo específico, esta guía usa JUnit en los ejemplos para que tengas algo concreto y completo con lo que trabajar. Antes de comenzar a escribir pruebas, necesitas agregar el JUnit 4 JAR apropiado a tu ruta de clase de pruebas. Una vez lo consigas, estarás listo para escribir una prueba simple de JUnit.
Si ejecutas Eclipse, selecciona el archivo fuente de la prueba que deseas ejecutar. Selecciona el menú Ejecutar > Ejecutar como > Prueba de JUnit. Los resultados de la prueba aparecen en la ventana de Console.
Ingresa las utilidades de prueba de Java 8
MyFirstTest
muestra la configuración de prueba más simple posible y, además, es posible que no necesites nada más para pruebas que no dependan de las API de App Engine o de implementaciones de servicios locales. Sin embargo, si tus pruebas o código bajo prueba tienen estas dependencias, agrega estos archivos JAR a tu ruta de clase de pruebas:
${SDK_ROOT}/lib/impl/appengine-api.jar
${SDK_ROOT}/lib/impl/appengine-api-stubs.jar
${SDK_ROOT}/lib/appengine-tools-api.jar
Estos JAR hacen que las API de entorno de ejecución y las implementaciones locales de esas API estén disponibles para las pruebas.
Los servicios de App Engine tienen ciertas expectativas de su entorno de ejecución y la configuración de estos implica una buena cantidad de código estándar. En lugar de configurarlo, puedes usar las utilidades del paquete com.google.appengine.tools.development.testing
. Para usar este paquete, agrega este archivo JAR a tu ruta de clase de pruebas:
${SDK_ROOT}/lib/testing/appengine-testing.jar
Dedica un minuto a explorar el javadoc para buscar el paquete com.google.appengine.tools.development.testing
. La clase más importante en este paquete es LocalServiceTestHelper, la cual maneja toda la configuración de entornos necesaria y te brinda un punto de configuración de nivel superior para todos los servicios locales a los que necesites acceder en tus pruebas.
Sigue estos pasos para escribir una prueba con acceso a un servicio local específico:
- Crea una instancia de
LocalServiceTestHelper
con una implementación deLocalServiceTestConfig
para ese servicio local específico. - Llama a
setUp()
en tu instanciaLocalServiceTestHelper
antes de cada prueba ytearDown()
después de cada prueba.
Escribe pruebas de Datastore y Memcache
En el ejemplo siguiente se prueba el uso del servicio de datastore.
En este ejemplo, LocalServiceTestHelper
configura y desglosa las partes del entorno de ejecución que son comunes a todos los servicios locales y LocalDatastoreServiceTestConfig
configura y desglosa las partes del entorno de ejecución que son específicas del servicio de almacén de datos local. Si lees el javadoc, verás que esto implica configurar el servicio de Datastore local para mantener todos los datos en la memoria (en lugar de limpiarlo al disco en intervalos regulares) y limpiar todos los datos en la memoria al final de cada prueba. Este es el comportamiento predeterminado de una prueba de Datastore y puedes cambiarlo si no es el que deseas.
Cambia el ejemplo para acceder a Memcache en lugar de Datastore
Para crear una prueba con acceso al servicio de Memcache local, debes usar el código que se muestra arriba, pero con unos pequeños cambios.
En lugar de importar clases relacionadas con Datastore, importa las clases con relación a Memcache. Aún debes importar LocalServiceTestHelper
.
Cambia el nombre de la clase que crees y cambia la instancia de LocalServiceTestHelper
para que sean específicos de Memcache.
Y por último, cambia el modo de ejecutar la prueba para que sea relevante a Memcache.
Al igual que en el ejemplo del almacén de datos, el LocalServiceTestHelper
y la LocalServiceTestConfig
específica del servicio (en este caso LocalMemcacheServiceTestConfig
) administran el entorno de ejecución.
Escribe pruebas de Cloud Datastore
Si tu app usa Cloud Datastore, puede que quieras escribir pruebas que verifiquen el comportamiento de tu aplicación ante una coherencia eventual. LocalDatastoreServiceTestConfig
expone las opciones que facilitan este proceso:
Si se configura el trabajo no aplicado al 100%, se le indica a Datastore local 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 podrán ver los cambios de manera constante. Por supuesto, esto no representa la cantidad de coherencia eventual que verá tu aplicación cuando se ejecute en la producción, pero configurar el Datastore local con el fin de que siempre se comporte de esta manera es muy útil para realizar pruebas.
Puedes registrar tu propia HighRepJobPolicy
si deseas un control más preciso sobre las transacciones que no se aplican:
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.
Escribe pruebas de lista de tareas en cola
Las pruebas que usan la lista de tareas en cola local están un poco más involucradas porque, a diferencia de Datastore y de Memcache, la API de la lista de tareas en cola no expone una instalación para examinar el estado del servicio. Es necesario acceder a la lista de tareas en cola local para verificar que se programó una tarea con los parámetros esperados. Para hacerlo, necesitamos com.google.appengine.api.taskqueue.dev.LocalTaskQueue
.
Observa cómo se le solicita a LocalTaskqueueTestConfig
un controlador de la instancia del servicio local y luego investígalo para asegurarte de que la tarea se programó como se esperaba. Todas las implementaciones de LocalServiceTestConfig
exponen un método similar. Puede que no siempre lo necesites, pero, tarde o temprano, te alegrará tenerlo allí.
Configura el archivo de configuración queue.xml
Las bibliotecas de prueba de la lista de tareas en cola permiten que se especifique cualquier cantidad de opciones de configuración queue.xml
por cada LocalServiceTestHelper a través del método LocalTaskQueueTestConfig.setQueueXmlPath
. Ahora, el servidor de desarrollo local ignora la configuración de límite de frecuencia de cualquier cola.
No es posible ejecutar tareas simultáneas de manera local.
Por ejemplo, puede que en un proyecto se necesite realizar pruebas con el archivo queue.xml
que subirá y usará la aplicación de App Engine. Si suponemos que el archivo queue.xml
está en la ubicación estándar, el código de muestra anterior podría modificarse de la siguiente forma para otorgar a la prueba acceso a las colas especificadas en el archivo src/main/webapp/WEB-INF/queue.xml
:
Modifica la ruta al archivo queue.xml
para que se ajuste a la estructura de archivo de tu proyecto.
Usa el método QueueFactory.getQueue
para acceder a las colas por nombre:
Escribe pruebas de tareas diferidas
Si el código de tu aplicación usa tareas diferidas, las utilidades de pruebas de Java facilitan la escritura de una prueba de integración que verifique los resultados de estas tareas.
Al igual que con nuestro primer ejemplo de lista de tareas en cola local, se usa una LocalTaskqueueTestConfig
, pero esta vez se inicializa con argumentos adicionales que permitan una manera fácil de verificar que no solo se programó la tarea, sino que también se ejecutó. Luego se llama a setDisableAutoTaskExecution(false)
para comunicarle a la lista de tareas en cola local que ejecute tareas de forma automática. Llamamos a setCallbackClass(LocalTaskQueueTestConfig.DeferredTaskCallback.class)
para que le comunique a la lista de tareas en cola local que use una devolución de llamada que comprenda cómo ejecutar tareas diferidas. Y por último, hay que llamar a setTaskExecutionLatch(latch)
para que le comunique a la lista de tareas en cola local que disminuya los bloqueos temporales después de ejecutar cada tarea. Esta configuración permite que se escriba una prueba en la que se pone en cola una tarea diferida y, después de que se ejecute, verifica que esta se haya comportado como se esperaba durante su ejecución.
Escribe pruebas de capacidades de servicio local
Las pruebas de capacidades implican el cambio del estado de un servicio, como Datastore, Blobstore, Memcache, etc., y ejecutar tu aplicación con el servicio para determinar si responde como se espera en distintas condiciones. El estado de capacidad se puede cambiar con la clase LocalCapabilitiesServiceTestConfig.
El siguiente fragmento de código configura el estado de capacidad del servicio de Datastore como inhabilitado y, luego, ejecuta una prueba en él. Se pueden sustituir otros servicios por Datastore según sea necesario.
Primero, la prueba de muestra crea un objeto Capability
inicializado en Datastore. Luego, crea un objeto CapabilityStatus
configurado como INHABILITADO. El LocalCapabilitiesServiceTestConfig
se crea con la capacidad y el estado configurados con los objetos Capability
y CapabilityStatus
que se acaban de crear.
El LocalServiceHelper
se crea mediante el objeto LocalCapabilitiesServiceTestConfig
. Ahora que se configuró la prueba, se crea el DatastoreService
y se le envía una consulta para determinar si la prueba genera los resultados que se esperan, en este caso, un CapabilityDisabledException
.
Escribe pruebas para otros servicios
Hay utilidades de pruebas disponibles para Blobstore y otros servicios de App Engine. Para obtener una lista de todos los servicios que tienen implementaciones locales para probar, consulta la documentación LocalServiceTestConfig
.
Escribe pruebas con expectativas de autenticación
En este ejemplo, se muestra cómo escribir pruebas que verifiquen lógica que usa UserService para determinar si un usuario inició sesión o si tiene privilegios de administrador. Ten en cuenta que cualquier usuario con la función básica de lector, editor o propietario, o la función predefinida de administrador de aplicaciones de App Engine tiene privilegios de administrador.
En este ejemplo, se configura LocalServiceTestHelper
con LocalUserServiceTestConfig
para que podamos usar UserService
en nuestra prueba, pero también se configuran algunos datos de entornos relacionados con la autenticación en el LocalServiceTestHelper
mismo.
En este ejemplo, estamos configurando LocalServiceTestHelper
con LocalUserServiceTestConfig
para que podamos usar OAuthService
.