Ciencia al descubierto
Automatización de pruebas en el desarrollo de productos de software

Software
El software, según la Real Academia Española (RAE), es el
"conjunto de programas, instrucciones y reglas informáticas
para ejecutar ciertas tareas en una computadora". Es decir,
se trata de todos aquellos componentes lógicos (ceros y
unos) que permiten la realización de tareas o funciones
específicas; el software es el encargado de enviar instrucciones
que el hardware ejecuta, lo que hace posible que los
artefactos de hardware funcionen, es decir, computadoras,
teléfonos celulares, impresoras, bocinas inteligentes, satélites,
sistemas de navegación de los aviones, sistemas de
control para las centrales de generación de energía eléctrica,
entre muchos otros ejemplos del mundo real.
En general, existe un acuerdo en que hay tres grandes tipos
de software:
- Software de sistema. Permiten la interacción directa con el hardware, por ejemplo: sistemas operativos, controladores de dispositivos, herramientas de diagnóstico, etcétera.
- Software de programación. Se trata del software que permite desarrollar software, es decir, son las herramientas, lenguajes de programación y utilerías para desarrollar software de aplicación, como: compiladores, intérpretes, enlazadores, depuradores, entornos de desarrollo integrados, librerías, entre otros.
- Software de aplicación. Son todos los paquetes, plataformas, herramientas y productos para los usuarios finales; realizan tareas específicas en cualquier ámbito de aplicación, por ejemplo: herramientas ofimáticas, control de procesos industriales, software educativo, software empresarial, bases de datos, páginas Web, videojuegos, asistentes médicos, diseño asistido, entre muchos otros.
En el ambiente del desarrollo de software, los principales actores son los llamados "desarrolladores"; quienes son expertos en software de programación, que conocen y dominan alguno o varios lenguajes de programación, pero en este mundo, saber programar no es suficiente para desarrollar productos de software de alta gama, con características específicas para el ámbito en el que debe funcionar, por ejemplo:
- Software para la industria militar, petrolera o energética.
- Software para vehículos terrestres, aéreos o espaciales.
- Software de alto rendimiento para supercomputadoras.
- Software de aplicación crítica, en tiempo real y con tolerancia a fallas.
- Software de grado empresarial.
Este tipo de "productos de software" se diferencia de las
"aplicaciones de software" en su grado de cumplimiento
funcional requerido. En los productos de software de alta
gama, las funciones integradas siempre deben ejecutarse
correctamente y hacer bien las secuencias, cálculos o algoritmos
que deben realizar. Se escucha muy sencillo y lógico,
pero esta característica es justamente la más compleja de
cumplir.
Para que un producto de software ejecute sus funciones
correctamente se requiere integrar un estricto control de
calidad durante todas las fases del desarrollo, desde el
inicio hasta el final.
Una función se especifica o define antes de empezar a
desarrollarla, para poder planear adecuadamente su comportamiento
y la manera en que debe resolver todos los
pasos o secuencias internas, sus entradas, algoritmos y
salidas, así como las condiciones y características específicas
(tiempo de respuesta, sincronización, precondiciones,
etc.). Durante su diseño, los especialistas determinan la
mejor manera de realizar la implementación dentro del
producto completo, así como las interacciones internas y
externas. Durante su desarrollo, los responsables realizan
la codificación de las funciones, cumpliendo las especificaciones
y diseño. Finalmente se prueba y se libera para su
integración en el producto completo.
La narrativa anterior describe la ruta ideal en el desarrollo,
pero en la vida real se requiere garantizar que todos los elementos que integran el producto de software
van a
operar como fueron definidos, para esto, las metodologías
de desarrollo de software guían al personal y grupos multidisciplinarios
para hacerlo bien con el menor esfuerzo o
retrabajo posible, siendo todos responsables de la calidad
de software en cada una de sus etapas; por lo tanto, las
pruebas de software son imprescindibles para generar cada
elemento del producto completo con la calidad adecuada.
Pruebas de software y su importancia en el desarrollo
Muchos desarrolladores tienen la anécdota de que, al
momento de entregar una función o incluso un producto
de software, el usuario le indica: "Esto no es lo que necesito",
es una historia de terror que le quita el sueño a los
desarrolladores, casi una pesadilla.
Un error que se comete de manera muy común, es pensar
más en la parte técnica y menos en lo que el usuario realmente
necesita. Se toman como base los requisitos y el
diseño, se interpretan las restricciones y se inicia el desarrollo
hasta su entrega. Pero ¿quién verifica que se estén
cumpliendo los requisitos originales?, ¿cómo se revisa
que los requisitos no funcionales están bien integrados? y ¿quién valida que se cumpla con las
necesidades del
usuario?
Realizar la verificación y validación de los requisitos es un
proceso fundamental en el ciclo de vida del desarrollo del
software; a este proceso se le conoce como
pruebas de
software
.
Las pruebas deben comenzar lo más pronto posible en el
proceso de desarrollo, ¿cómo es esto posible si aún no se
tiene algo funcionando?
Las pruebas se pueden clasificar como estáticas y dinámicas.
Las pruebas estáticas son cuando se verifica la
documentación desde el análisis de requisitos, diseño de
los procesos de negocio, historias de usuario, casos de uso,
documentos técnicos o el cumplimiento con alguna restricción
definida (tiempo, sincronización, seguridad, etc.). Las
pruebas dinámicas están relacionadas con la ejecución y
pruebas funcionales del producto de software.
Dentro de las pruebas dinámicas existe una sub-clasificación
que se muestra en la Figura 1, en donde se aprecia de
manera visual la proporción de pruebas que se recomienda
realizar, siendo la de mayor proporción las pruebas unitarias
y en menor proporción las pruebas funcionales.

Figura 1. Pirámide de pruebas automatizadas.
Al ejecutar pruebas estáticas se verifica en una etapa "temprana"
la posible introducción de errores en el código, ya que
se podrían interpretar erróneamente los requisitos, lo cual
provocará un mal diseño e impactará en los componentes y,
por lo tanto, tendrá un mal funcionamiento integrado. La pregunta
entonces es: ¿cuánto tiempo llevará resolver una mala
interpretación que se pudo identificar al inicio del proceso?
La aplicación de pruebas tempranas es uno de los principios
fundamentales de las pruebas de software, permiten
conocer si los desarrolladores están comprendiendo el
negocio, si se está desarrollando un producto acorde a los
requisitos y, sobre todo, si se están cumpliendo las necesidades
del usuario; adicionalmente, en cuestiones monetarias,
se logra un ahorro considerable que será reflejado en
el mantenimiento del producto.
Cuando se liberan las primeras versiones de un producto de
software, las pruebas manuales suelen ser muy efectivas, ya
que una persona verifica que los requisitos se cumplan, que
el sistema funcione, que la interfaz gráfica se vea "bonita", que
no existan problemas en el acceso al sistema, etc. Sin embargo,
conforme el producto va creciendo, la probabilidad de introducir
errores en el código se vuelve más alta y las pruebas se
vuelven más complejas, ya que hay que verificar el incremento
en las funciones y, además, hay que verificar que todo lo desarrollado
previamente no ha sufrido cambios, a esto se le llama
pruebas de regresión.
Con las pruebas de regresión se vuelve a probar lo que ya se
había dado por bueno, con la finalidad de que, al ir incrementando
el desarrollo del producto, este no se vea afectado.
Las pruebas de regresión también se pueden realizar de
forma manual, pero es muy tedioso estar repitiendo una,
y otra, y otra, y otra vez... las mismas pruebas, al volverse
un proceso "aburrido", el personal encargado tiende a no
identificar ciertos aspectos y dejan pasar muchos errores.
Afortunadamente, en muchos contextos, los procesos
"repetitivos" se pueden "automatizar" y las pruebas de
software no son la excepción.
Automatización de las pruebas
Las pruebas automatizadas ayudan a ejecutar adecuadamente
los procesos tediosos. Básicamente funcionan como
lo haría una persona, realizan aquellas acciones que se
hacían de forma manual, pero en un tiempo más corto y
sin incertidumbre.
Por ejemplo, en las pruebas unitarias, que consisten en
probar los componentes de forma aislada, se pueden utilizar
metodologías de desarrollo de software basada en
pruebas, conocidas como: Test Driven Development o TDD
(Desarrollo Basado en Pruebas, por sus siglas en inglés) y
utilizar marcos de trabajo como: JUnit, NUnit, TestNG, QUnit,
lo cual dependerá del lenguaje de programación utilizado
en el desarrollo.
Para el caso de la automatización de las pruebas funcionales,
pueden ser desde muy sencilla, hasta muy compleja;
por ejemplo, con las herramientas Selenium IDE o Katalon,
se pueden realizar grabaciones de las acciones realizadas
en la navegación de un producto de software y después
volver a ejecutarlas, una o muchas veces. La desventaja de
este tipo de automatización es que, si algún componente
del producto es modificado, se tienen que realizar nuevamente
las grabaciones para poder ejecutar las pruebas.
De igual forma se pueden realizar pruebas automatizadas
mucho más complejas, utilizando herramientas como:
Selenium Webdriver, Testcafé, Cypress, Calabash, Appium o
Capybara; en donde el encargado de las pruebas implementa
código fuente en diversos lenguajes de programación
como: java, javascript o ruby, para "simular" las
acciones en la navegación de un producto de software. En
este tipo de pruebas, si un componente del producto es
modificado, únicamente se tienen que actualizar las referencias
del componente en el código y volver a ejecutar las
pruebas.
¿Quién debe aplicar las pruebas?
Realizar pruebas automatizadas no es un trabajo fácil, el responsable debe tener cualidades personales específicas, debe ser creativo para diseñar los casos de pruebas, analítico para identificar los diversos escenarios del negocio, curioso para preguntarse ¿qué pasa sí...? ¿por qué no hacer algo de otra forma?, desconfiando para ejecutar diversos escenarios en cada nueva versión del producto y tener muy buena comunicación para informar los "defectos" encontrados; además, debe tener conocimientos técnicos en lenguajes de programación, herramientas de automatización, herramientas de integración, sistemas de control de versiones e ingeniería de software.

Experiencia en el INEEL
Algunas de las áreas técnicas del INEEL tienen entre sus
funciones más relevantes el desarrollo de productos de
software de alta gama o de grado empresarial, algunos son
de misión crítica para el sector energético en México, por
ejemplo, para la CFE, PEMEX y CENACE, entre otros.
Hasta hace algunos años, los desarrollos requerían de una
gran cantidad de tiempo por parte de los desarrolladores
para verificar el correcto funcionamiento de sus productos,
debido a que el proceso de pruebas se llevaba a cabo de
manera manual o semi-automático.
La necesidad de adoptar metodologías modernas para el
desarrollo ágil, que impulsen el desarrollo iterativo, que
permitan aumentar la calidad de los productos desarrollados
y disminuir el tiempo que invierten los desarrolladores
para probar el software, fue un gran motivador para
iniciar la implementación de pruebas automatizadas de
software.
Primeramente, se elaboró un proyecto piloto, en el cual
se implementaron pruebas automatizadas funcionales
(pruebas desde la IHM), este proyecto piloto mostró los beneficios potenciales que se podían obtener en
los diferentes desarrollos de productos de software.
Posteriormente se definieron los proyectos cuyos productos
de software tienen características especiales, por
ejemplo, un sistema de aplicación crítica, en tiempo real y
con tolerancia a fallas, en cual se implementaron pruebas
automatizadas, no sólo funcionales, sino también unitarias
y de integración.
En estos proyectos de desarrollo de software, los desarrolladores
deben realizar las pruebas unitarias dependiendo
del lenguaje que estén utilizando (Go, C#, Javascript,
Typescript) y con algún marco de trabajo, propio para el
lenguaje, por ejemplo, NUnit para C#. Las pruebas unitarias
se enfocaron a probar de manera aislada a los módulos,
clases, métodos o funciones de los componentes del
software. Las pruebas de integración se realizaron con un
marco de trabajo dependiente del lenguaje de programación
y por un desarrollador diferente al responsable de la
codificación original.
Para las pruebas funcionales, se definió a un grupo de
desarrolladores que se encargan de realizar las pruebas
automatizadas utilizando Selenium y dependiendo del proyecto,
se utiliza C# o Java.
La implementación de pruebas automatizadas en este tipo
de proyectos no es sencilla, ya que se requiere la integración
de una gran cantidad de tecnología, pero una vez
superados los retos tecnológicos, se obtienen mejoras sustanciales,
tanto en los procesos de desarrollo, como en el
producto de software, y, por lo tanto, en la satisfacción del
usuario.
Factores que pueden afectar la automatización de las pruebas
Existen varios factores a tomar en cuenta al momento de implementar la automatización de pruebas, entre ellos:
- La falta de experiencia de los desarrolladores en pruebas unitarias puede provocar que el código sea muy frágil, por lo que cualquier cambio en el código fuente del producto puede provocar que la prueba falle.
- El código fuente de las pruebas se debe considerar en igualdad de importancia al código fuente del producto de software. Esto no es fácil de asimilar, debido a que los desarrolladores acostumbran avanzar en el desarrollo de la funcionalidad y al final realizar las pruebas.
- Las presiones de entrega en tiempo pueden provocar que las pruebas unitarias se visualicen como una actividad que retrasa al desarrollador.
Beneficios de la automatización de las pruebas
El beneficio más tangible es contar con la capacidad de
ejecutar todas las pruebas (unitarias, de integración y funcionales)
en tiempos muy cortos (minutos), en lugar de
las horas o días que lleva realizar las pruebas de manera
manual. Esta agilidad permite verificar de manera muy
rápida si alguno de los cambios o nuevas funcionalidades
realizadas afecta el funcionamiento del componente o del
sistema, y de ser el caso, poder realizar la corrección antes
de la liberación correspondiente.
Otro beneficio menos tangible, pero muy relevante, es que,
al contar con pruebas automatizadas es posible implementar
un marco de trabajo para la integración continua
(constantemente probar y generar las aplicaciones), esto
se realiza mediante herramientas como: Jenkins, GitLab CI,
TeamCity, entre otras, en conjunto con las herramientas
para la automatización de las pruebas.
Finalmente, el cambio de paradigma al utilizar pruebas
automatizadas, también incluye el beneficio adicional de
que la estructura del código de los productos de software,
mejora mediante la aplicación de patrones y técnicas de
código limpio, lo que genera productos más robustos y con
mayor facilidad para su mantenimiento en el tiempo.
Autores:
Raúl García Mendoza, rgarcia@ineel.mx
Alejandra Arelí Molina Gómez, molina024@gmail.com
Alfredo Espinosa Reza, aer@ineel.mx