Las pruebas de interfaz de usuario automatizadas son un tema que incluso los desarrolladores experimentados desconfían. Además, la tecnología de tales pruebas no es algo extraordinario, y en el caso de las Pruebas de IU codificadas de Visual Studio es una extensión del sistema de pruebas de unidad incorporado Visual Studio Team Test. En este artículo, quiero profundizar en el tema de las pruebas de IU en general, así como en nuestra experiencia personal de usar las pruebas de IU codificadas de Visual Studio al trabajar en el analizador estático PVS-Studio.
Los fundamentos
Primero, intentemos descubrir por qué las pruebas de IU no son tan populares entre los desarrolladores como, por ejemplo, las pruebas unitarias clásicas.
Hay muchas llamadas "pirámides de prueba" en la red que muestran la distribución óptima recomendada del número de pruebas en las capas de aplicación. Todas las pirámides son similares y contienen una idea general: tantas pruebas como sea posible deberían estar lo más cerca posible del código. Y viceversa. Daré un ejemplo de una de estas pirámides, que contiene recomendaciones adicionales sobre la proporción del número de pruebas en porcentaje.

En la base de la pirámide hay pruebas unitarias. De hecho, tales pruebas son más fáciles de hacer en la etapa de desarrollo y se ejecutarán muy rápidamente. En la parte superior de la pirámide, por otro lado, hay pruebas de interfaz automatizadas. Estas pruebas no deberían ser muchas, ya que la complejidad de su creación, así como el tiempo de ejecución, son bastante grandes. Además, no está claro a quién confiar la creación de pruebas de IU. De hecho, en esencia, estamos hablando de emular las acciones del usuario. Todo esto está muy lejos del código de la aplicación, por lo que los desarrolladores son reacios a hacer este tipo de trabajo. Y para realizar pruebas automatizadas de alta calidad de las interfaces sin la participación (o con una participación mínima) de los programadores, se requiere el uso de herramientas pagas. La combinación de todos estos factores a menudo conduce al hecho de que las pruebas de IU no funcionan en absoluto, limitándose a pruebas manuales únicas de nuevas funcionalidades. Además, las pruebas de interfaz son extremadamente costosas no solo en la etapa de desarrollo, sino también durante el ciclo de vida de la aplicación. Incluso un ligero cambio en la interfaz de usuario puede provocar errores en la ejecución de muchas pruebas y la necesidad de modificarlas.
Observo que en la actualidad, nuestro sistema de prueba en general cumple con las recomendaciones. El número de pruebas de GUI automatizadas (45) es aproximadamente una décima parte del número total de pruebas de PVS-Studio. Al mismo tiempo, el número de pruebas unitarias no es tan grande, pero se complementan con una gran cantidad de otros sistemas de prueba:
- Pruebas de rendimiento de analizadores (C / C ++ / C # / Java), durante las cuales verifican un gran conjunto de proyectos de prueba en diferentes sistemas operativos (Windows, Linux, macOS) y comparan los registros de nuevas advertencias con los de referencia;
- Pruebas de características específicas (seguimiento del lanzamiento de compiladores, etc.);
- Pruebas externas de aplicaciones de línea de comandos;
- Pruebas de montaje, instalación y despliegue correctos;
- Pruebas de documentación.
En la etapa inicial de su desarrollo, el analizador PVS-Studio era una aplicación para encontrar errores al portar código C / C ++ a una plataforma de 64 bits. Sí, y fue llamado en ese momento de una manera diferente, "Viva64". La historia del producto se puede encontrar en el artículo "
Cómo comenzó el proyecto PVS-Studio hace 10 años ". Después de la integración en Visual Studio 2005, el analizador adquirió una interfaz gráfica de usuario, esencialmente la interfaz del IDE de Visual Studio, en la cual, después de instalar el complemento, apareció un menú adicional para acceder a la funcionalidad del analizador. El menú tenía dos o tres elementos, por lo que no había nada que probar allí. Y Visual Studio en ese momento no contenía ninguna herramienta integrada para probar las GUI.
Pruebas y alternativas de IU codificadas de Visual Studio
Todo cambió con el lanzamiento de Visual Studio 2010, que introdujo un sistema integrado para crear pruebas de IU: Pruebas de IU codificadas de Visual Studio (CUIT). Basado en el sistema de prueba de la unidad Visual Studio Team Test, CUIT inicialmente utilizó la tecnología Microsoft Active Accessibility (MSAA) para acceder a los elementos de la interfaz visual. En el futuro, la tecnología se mejoró y actualmente es un modelo desarrollado de automatización de la interfaz de usuario para probar el código UIA (UI Automation). Permite que el sistema de prueba acceda a campos abiertos (nombre del objeto, nombre interno de la clase del objeto, estado actual del objeto, su lugar en la estructura jerárquica de la interfaz, etc.) de los elementos COM y .NET UI, y el sistema le permite emular los efectos en estos elementos a través de dispositivos de entrada estándar (mouse, teclado). Desde el primer momento, se admiten modos para registrar las acciones del usuario cuando interactúa con la interfaz (similar a las macros de Visual Studio), la automatización de la construcción de un "mapa de interfaz" (propiedades de controles, parámetros de búsqueda y acceso a ellos), junto con la generación automática de código de control. En el futuro, toda la información acumulada es fácil de modificar y mantener actualizada, así como personalizar las secuencias de prueba que desee, al tiempo que posee habilidades mínimas de programación.
Además, como dije antes, ahora al crear complejas pruebas de IU inteligentes, puede prescindir de cualquier habilidad de programación, siempre que use herramientas especializadas pagas. Bueno, si no hay deseo o capacidad de usar entornos de prueba patentados, hay muchos productos y marcos gratuitos. El sistema de Pruebas de IU codificadas de Visual Studio es una solución intermedia que permite no solo automatizar el proceso de creación de pruebas de IU tanto como sea posible. Con su ayuda, es fácil crear secuencias de prueba arbitrarias en los lenguajes de programación C # o VB.
Todo esto puede reducir significativamente el costo de crear y mantener la relevancia de las pruebas de GUI. El marco utilizado es simple de entender y, en general, se puede representar en forma de diagrama.
De los elementos clave, deben tenerse en cuenta los llamados "adaptadores de interfaz", que se encuentran en el nivel más bajo de abstracción. Esta capa interactúa con los elementos finitos de la interfaz de usuario, y sus capacidades se pueden ampliar utilizando adaptadores adicionales. Arriba hay una capa que oculta las tecnologías de acceso a la GUI del resto del código, incluidas las interfaces de acceso al programa y el código de la aplicación de prueba real, que incluye todos los elementos necesarios para probar la automatización. La tecnología es extensible, cada nivel puede complementarse con los elementos necesarios dentro del marco del marco.
Las características principales de CUIT de Microsoft incluyen:
- Pruebas funcionales de interfaces de usuario. Se admiten aplicaciones clásicas basadas en Windows, aplicaciones web y servicios, WPF
- Generación de código (incluido automático) en VB / C #
- Capacidad para integrarse en el proceso de ensamblaje
- Lanzamientos locales o remotos, recopilación de informes
- Disponibilidad de grabación y reproducción de secuencias de prueba.
- Buena extensibilidad
A pesar de una serie de dificultades asociadas con CUIT, se prefiere el uso de esta tecnología de prueba por varias razones:
- Interacción efectiva de desarrolladores y probadores dentro de una herramienta y lenguaje de programación
- Características adicionales de trabajar con la "tarjeta de interfaz", que permite la identificación de controles "sobre la marcha", la sincronización de elementos y la realización de secuencias de prueba
- Afinando el mecanismo de reproducción, que permite junto con configuraciones básicas, como un retraso entre operaciones, un tiempo de espera de búsqueda de elementos, etc., utilizar mecanismos especializados en el código. Por ejemplo, bloquear el subproceso actual hasta que el control se active (visualice) utilizando los métodos WaitForControlExist o WaitForReady con la enumeración WaitForReadyLevel , etc.
- Capacidad para programar pruebas ilimitadamente complejas
No profundizaré en los aspectos teóricos de la tecnología de Pruebas de IU codificadas de Visual Studio, todos se detallan en la documentación pertinente. Allí puede encontrar instrucciones detalladas paso a paso para crear la prueba de IU más simple basada en este sistema. Y sí, el sistema no es gratuito, necesitará Visual Studio Enterprise para trabajar con él.
La tecnología descrita no es la única en el mercado. Hay muchas otras soluciones. Todos los sistemas alternativos de prueba de IU se pueden dividir en pagos y gratuitos. Además, la elección de un sistema en particular no siempre dependerá de su precio. Por ejemplo, la capacidad de crear pruebas sin la necesidad de programación puede servir como un factor importante, pero al mismo tiempo, las pruebas pueden no ser lo suficientemente flexibles. También es importante admitir el entorno de prueba necesario: sistemas operativos y aplicaciones. Finalmente, las características puramente específicas de la aplicación y su interfaz pueden influir en la elección. Aquí hay algunos sistemas y tecnologías populares para probar las GUI.
Pagado :
TestComplete (SmartBear),
Prueba funcional unificada (Micro Focus),
Squish (froglogic),
Herramientas de prueba automatizadas (Ranorex),
Berenjena funcional (berenjena), etc.
Gratis :
AutoIt (windows),
Selenium (web),
Katalon Studio (web, móvil),
Sahi (web),
Robot Framework (web),
LDTP (Linux Desktop Testing Project), marcos de código abierto:
TestStack.White +
UIAutomationVerify,. NET biblioteca de automatización de Windows , etc.
Por supuesto, esta lista no está completa. Sin embargo, es obvio que los sistemas libres generalmente se centran en un sistema operativo específico o tecnología de prueba. La regla general es que entre los sistemas pagos encontrará mucho más rápido algo adecuado específicamente para sus necesidades, el desarrollo y mantenimiento de las pruebas será más fácil y la lista de entornos de prueba compatibles es exhaustiva.
En nuestro caso, no había ningún problema de elección: con el lanzamiento de Visual Studio 2010 con la adición de Pruebas de IU codificadas, se hizo posible agregar fácilmente un conjunto de pruebas funcionales a nuestro entorno de prueba para probar la interfaz de usuario del complemento PVS-Studio para Visual Studio.
PVS-Studio UI pruebas
Por lo tanto, las pruebas de GUI en nuestra empresa se han utilizado durante más de 6 años. El conjunto inicial de pruebas de IU para Visual Studio 2010 se basó en la única tecnología MSAA (Microsoft Active Accessibility) disponible en ese momento. Con el lanzamiento de Visual Studio 2012, la tecnología MSAA se ha desarrollado significativamente y ahora se llama UIA (UI Automation). Se decidió continuar usando el UIA y dejar las pruebas basadas en MSAA para probar el complemento para Visual Studio 2010 (admitimos y probamos complementos para todas las versiones de Visual Studio, comenzando con Visual Studio 2010).
Como resultado, hemos formado dos "ramas" de pruebas de IU. Además, en el proyecto de prueba, ambas ramas utilizaron un mapa de interfaz común y un código compartido. En el código, se parecía a esto (método para restablecer la configuración de Visual Studio a estándar antes de ejecutar la prueba):
public void ResetVSSettings(TestingMode mode) { .... #region MSAA Mode if (mode == TestingMode.MSAA) { .... return; } #endregion
Al realizar cambios en la interfaz del complemento, fue necesario realizar cambios en ambas ramas de las pruebas de IU, y agregar nuevas funcionalidades hizo necesario duplicar el elemento de la interfaz en el mapa: es decir, crear dos elementos diferentes para cada una de las tecnologías MSAA y UIA. Todo esto requirió mucho esfuerzo no solo para crear o modificar pruebas, sino también para mantener el entorno de prueba en un estado estable. Me detendré en este aspecto con más detalle.
Según mis observaciones, la estabilidad del entorno de prueba cuando se prueba la GUI es un problema importante. Esto se debe principalmente a la fuerte dependencia de tales pruebas de muchos factores externos. De hecho, de hecho, las acciones del usuario son emuladas: presionar teclas, mover el cursor del mouse, clics del mouse, etc. Hay muchas cosas que pueden "salir mal". Por ejemplo, si durante la prueba alguien interactúa con un teclado conectado al servidor de prueba. Además, inesperadamente, la resolución del monitor puede no ser suficiente para mostrar ningún control y el entorno de prueba no la encontrará.
En espera:
Realidad:
Un elemento de mapa de interfaz sintonizado descuidadamente (y no encontrado más adelante) es prácticamente el líder del comportamiento problemático. Por ejemplo, al crear un nuevo control, el asistente de mapa de interfaz de Pruebas de IU codificadas de Visual Studio usa los criterios de búsqueda Equals predeterminados para él. Es decir, se requiere una coincidencia exacta de los nombres de propiedad con los valores especificados. Esto generalmente funciona, pero a veces la estabilidad de la ejecución de la prueba se puede mejorar significativamente utilizando los criterios de búsqueda menos estrictos "Contiene" en lugar de "Igual". Este es solo un ejemplo de un "ajuste" que puede encontrar al trabajar en pruebas de IU.
Finalmente, algunas de sus pruebas pueden consistir en realizar una acción y esperar aún más un resultado, que, por ejemplo, está asociado con la visualización de una ventana. En este caso, al problema de buscar un elemento, se agregarán preguntas sobre cómo configurar el retraso de reproducción hasta que aparezca la ventana y luego sincronizar el trabajo. Algunos de estos problemas pueden resolverse mediante métodos de marco estándar (
WaitForControlExist , etc.), mientras que para otros será necesario inventar algoritmos ingeniosos.
Nos enfrentamos a un problema similar mientras trabajábamos en una de las pruebas de nuestro complemento. En esta prueba, primero se abre un entorno de Visual Studio vacío, luego se carga una determinada solución de prueba, que se prueba completamente usando PVS-Studio (menú “PVS-Studio” -> “Verificar” -> “Solución”). El problema era determinar cuándo se completaría la verificación. Dependiendo de una serie de condiciones, la verificación puede no tomar siempre el mismo tiempo, por lo que los tiempos de espera simples no funcionan aquí. Además, no puede utilizar los mecanismos estándar para suspender el flujo de prueba y esperar la aparición (u ocultación) de ningún control, ya que no hay nada a lo que apegarse. Durante la verificación, aparece una ventana con el estado del trabajo, pero esta ventana puede ocultarse y la verificación continuará. Es decir esta ventana no se puede guiar (además, tiene la configuración "No cerrar después de completar el análisis"). Y quería que el algoritmo fuera más general para poder usarlo en varias pruebas relacionadas con la verificación de proyectos y la espera de la finalización de este proceso. Se ha encontrado una solución. Después de comenzar la prueba y hasta su finalización, el mismo elemento del menú "PVS-Studio" -> "Verificar" -> "Solución" está inactivo. Solo tuvimos que verificar la propiedad "Habilitado" de este elemento del menú en un intervalo de tiempo determinado (a través del objeto de mapa de interfaz) y, si se descubrió que el elemento se había activado, considerar el proceso de verificación de decisión completo.
Por lo tanto, en el caso de las pruebas de IU, no es suficiente simplemente crear pruebas. Se requiere una sintonización sutil y meticulosa en cada caso. Es necesario comprender y sincronizar toda la secuencia de acciones realizadas. Por ejemplo, el elemento del menú contextual no se encontrará hasta que este menú se muestre en la pantalla, etc. También se requiere una preparación cuidadosa del entorno de prueba. En este caso, puede contar con el funcionamiento estable de las pruebas y los resultados adecuados.
Permítame recordarle que el sistema de pruebas de IU en nuestra empresa se ha desarrollado desde 2010. Durante este tiempo, se crearon varias docenas de secuencias de prueba y se escribió una gran cantidad de código auxiliar. Las pruebas de aplicaciones independientes se han agregado a las pruebas de complementos a lo largo del tiempo. En este punto, la antigua rama de prueba de complementos para Visual Studio 2010 había perdido su relevancia y fue abandonada, pero era simplemente imposible eliminar este código "muerto" del proyecto. En primer lugar, como mostré antes, el código estaba bastante integrado en los métodos de prueba. Y en segundo lugar, más de la mitad de los elementos de la tarjeta de interfaz existente pertenecían a la antigua tecnología MSAA, pero se reutilizaron (en lugar de duplicar) en muchas pruebas nuevas junto con elementos UIA (esto es posible debido a la continuidad de la tecnología). Al mismo tiempo, la masa del código generado automáticamente y el contenido de los métodos de prueba estaba vinculado a los elementos "antiguos".
Para el otoño de 2017, era necesario mejorar el sistema de pruebas de IU. En general, las pruebas funcionaron bien, pero de vez en cuando algunas "fallaron" por razones desconocidas. Más precisamente, la razón generalmente era encontrar un control. En cada caso, tuve que ir a través del árbol del mapa de interfaz a un elemento específico y verificar sus criterios de búsqueda y otras configuraciones. A veces, un reinicio del software de estas configuraciones ayudó antes de ejecutar la prueba. Dado el mapa de interfaz que ha crecido (y en muchos aspectos, de muchas maneras) por la tarjeta de interfaz, así como la presencia de código "inactivo", este proceso requirió un esfuerzo considerable.
Durante algún tiempo, la tarea "estaba esperando a su héroe", hasta que, finalmente, se me ocurrió.
No te aburriré con una descripción de los matices. Solo puedo decir que el trabajo no fue difícil, pero requirió considerable perseverancia y atención. Todo sobre todo me llevó unas dos semanas. Pasé la mitad de este tiempo refactorizando el código y las tarjetas de interfaz. En el tiempo restante, se dedicó a la estabilización de la ejecución de la prueba, que básicamente se redujo a un ajuste más fino de los criterios de búsqueda de elementos visuales (edición del mapa de la interfaz), así como a una cierta optimización del código.
Como resultado, logramos reducir el tamaño del código de los métodos de prueba en aproximadamente un 30%, y la cantidad de controles en el árbol del mapa de interfaz se redujo a la mitad. Pero lo más importante, las pruebas de IU comenzaron a mostrar un rendimiento más estable y requieren menos atención. Y la caída comenzó a ocurrir con mayor frecuencia debido a razones para realizar cambios en la funcionalidad del analizador o al detectar inconsistencias (errores). En realidad, para estos fines, necesitamos un sistema de pruebas de IU.
Por lo tanto, en la actualidad, el sistema de pruebas automáticas de la interfaz PVS-Studio tiene las siguientes características básicas:
- Prueba de IU codificada de Visual Studio
- 45 escenarios
- 4,095 líneas de código para métodos de prueba
- 19,889 líneas de código generado automáticamente (excluyendo el tamaño del archivo xml para almacenar la configuración del Mapa de la IU)
- 1 hora 34 minutos de ejecución (valor promedio de acuerdo con los resultados de los últimos 30 inicios)
- Trabajar en un servidor dedicado (ejecutando la utilidad MSTest.exe)
- Monitoreo de rendimiento y análisis de informe de rendimiento (Jenkins)
Conclusión
En conclusión, quiero dar una lista de criterios de éxito para las pruebas de GUI automáticas, que se basa en un análisis de nuestra experiencia con esta tecnología (algunos de los criterios se aplican a otras tecnologías de prueba, por ejemplo, pruebas unitarias).
Herramientas adecuadas Elija el entorno para crear y ejecutar CUIT de acuerdo con las características de su aplicación, así como el entorno de prueba. Las soluciones pagas no siempre tienen sentido, pero generalmente ayudan a resolver un problema de manera muy efectiva.
Configuración de infraestructura de alta calidad . No guarde al desarrollar una tarjeta de interfaz. Simplifique el trabajo del marco cuando busque elementos describiendo cuidadosamente todas sus propiedades y estableciendo criterios de búsqueda inteligentes. Presta atención a las posibilidades de modificaciones adicionales.
Minimización del trabajo manual . Siempre que sea posible, asegúrese de utilizar medios automáticos para generar código y grabar secuencias. Por lo tanto, acelerará significativamente el desarrollo y minimizará la probabilidad de errores (no siempre es fácil encontrar la razón por la cual la prueba de IU falla, especialmente si se comete un error en el código para trabajar con el marco).
Pruebas inteligentes simples e independientes . Cuanto más simples sean tus exámenes, mejor. Intente hacer una prueba por separado para probar un control específico o una situación simulada. También asegúrese de que las pruebas sean independientes entre sí. La caída de una de las pruebas no debería afectar todo el proceso.
Nombres amistosos . Use prefijos en los nombres de pruebas similares. Muchos entornos le permiten ejecutar pruebas filtrando por nombre. Utilice también la agrupación de prueba siempre que sea posible.
Tiempo de ejecución aislado . Asegúrese de que las pruebas se ejecuten en un servidor dedicado con un impacto externo mínimo. Desconecte todos los dispositivos de entrada de usuario externos, proporcione la resolución de pantalla necesaria para su aplicación o use un dispositivo ficticio de hardware que simule una conexión de monitor de alta resolución. Asegúrese de que durante la ejecución de la prueba no se ejecuten otras aplicaciones que interactúen, por ejemplo, con el escritorio y los mensajes de pantalla. También es necesario planificar la hora de inicio y considerar la duración máxima de las pruebas.
Análisis de informes emitidos . Proporcione una forma simple y clara para informar sobre el progreso. Utilice sistemas de integración continua para enviar pruebas, así como obtener y analizar rápidamente los resultados de las pruebas.

Si desea compartir este artículo con una audiencia de habla inglesa, utilice el enlace a la traducción: Sergey Khrenov.
Pruebas de IU codificadas de Visual Studio: teoría y experiencia de usuario de nuestra empresa