En anteriores publicaciones he resaltado la importancia de realizar pruebas como guía para mejorar el producto software. Y es que la importancia es tal, que permite orientar el desarrollo a la consecusión de requerimientos y, por lo tanto, los objetivos de negocio. Sí, y por supuesto, sabes que es importante, suena lógico que es necesario tener evidencia de que lo que codificas de verdad funciona, pero entonces, ¿como hacerlo? Esto es lo que verémos a continuación.
1. Introducción
Bienvenido a esta serie de artículos dedicados a las pruebas de software que se orientan a profundizar, de manera integra, los conceptos necesarios para lograr definirlas y ejecutarlas. ¡Comencemos!
Existen diversos tipos de pruebas para orientar el desarrollo de software. Dependiendo de las necesidades, es posible tener un control más estricto del flujo de contról de código, manteniendo la consistencia y aportanto visibilidad del contenido del mismo hasta en el valor de cada una de las variables definidas. Este tipo de pruebas se conoce como caja blanca puesto que permiten ver absolutamente todo el funcionamiento del código. Sin embargo, por lo general, tener el control completo del flujo del mismo, consume muchos recursos de tiempo y esfuerzo y no es necesario tener una visibilidad completa, sino únicamente en secciones donde estamos interesados en realizar su depuración.
Otras soluciones se destacan por tener el control suficiente para conocer únicamente que el código efectivamente produce las salidas esperadas. Este tipo de pruebas se conocen como caja negra, puesto que no se conoce el contenido de los datos que el código puede tener en una linea en especifico, sin embargo, se conoce el resultado final del mismo.
2. Pruebas unitarias
Dentro de las pruebas de caja negra destacan las pruebas unitarias, las cuales se enfocan en las salidas de las secciones de un código donde, por lo general, van acompañadas por medio de, así mismo, código software. ¡Así es! Escribes código para probar código.
Dentro de las pruebas unitarias se manejan diversos conceptos que son de utilidad al momento de enfrentarte al código sea cual sea su lenguaje, a continuación, indicarémos aquellos que son los más importantes:
- Asserts: Los asserts son el núcleo de las pruebas unitarias, son el por qué de su existencia, porque especifícas con ellas como comparas los objetos de código, donde generalmente se comparan tipos de datos primitivos. Finalmente, los asserts son las palabras reservadas dentro del código de las pruebas unitarias en las que esperas que las salidas de tu código presenten los resultados que indicas.
- Inicializadores: Los inicializadores son a las pruenas unitarias como los constructores a las clases, son funciones que declaran o inicializan objetos concretos de tipos de datos.
- Finalizadores: Son una especie de “desctructores”, sin que signifiquen la destrucción del objeto de pruebas creado. Tal como en los constructores, se ejecutan tras finalizar su ejecución.
- Mocks: Son vitales al momento de la creación de objetos de clases altamente acopladas, y se utilizan para mentir la creación de instancias de objetos de las cuales depende dicha clase con la creación de objetos vacios usados dentro de la clase acoplada. Esto es especialmente útil al momento de probar instancias de clases como la principal, la cual instancia todas las clases en cadena de una aplicación, ignorando la problematica creación de las instancias de clase, y centrando al desarrollador en probar el contenido de la clase como tal.
Este tipo de prueba es tan popular, que los lenguajes más populares de programación ya tienen librerías que soportan este tipo de pruebas, inclusive los IDE’s ya lo soportan de manera gráfica.
| Lenguaje | Librerías de pruebas unitarias | IDE's |
|---|---|---|
| Javascript | Jest, Jasmine, Mocha | Webstorm |
| Java | Junit | Eclipse, Netbeans |
| Python | Pytest | PyCharm, PyDev, Spider |
| PHP | PHPUnit | PHPStorm |
| C++ | Google Test | Qt Creator, CLion |
3. Cobertura de pruebas unitarias
La cobertura consiste en detectar qué tanto código software han cubierto las pruebas unitarias con el objetivo de detectar las lineas de código probadas y las que aún falta por probar.
En la cobertura, se considera cubierta una sección de código en los siguientes casos: (i) que las pruebas ejecuten efectivamente los componentes de código que han sido llamados, (ii) que efectivamente las pruebas unitarias ejecutadas pasen los asserts y la ejecución correcta de las pruebas, incluyendo el llamado de las dependencias y (iii) que se ignore explicitamente una sección de código por el programador.
Así mismo, existen IDE’s que soportan gráficamente la visualización de estos dos escenarios.
| Lenguaje | Librerías de cobertura | IDE's |
|---|---|---|
| Javascript | jscoverage | Webstorm |
| Java | JaCoCo | Eclipse, Netbeans |
| PHP | Xdebug | PHPStorm |
| C++ | lcov | Qt Creator |
Nota: Las tablas anteriores presentan los IDE’s que soportan las librerías de pruebas unitarias y de cobertura de forma gráfica, pero todos pueden ejecutar estas dos características así sean por comandos y generando informes en html, xml, json y otros.
4. Ejemplo
Consideraremos el siguiente ejemplo de una clase en java donde es necesario realizar la verificación de una de sus funciones:
public class Suma {
private int a;
private int b;
public Suma (int a, int b){
this.a = a;
this.b = b;
}
public int sumar(){
return a+b;
}
}
La clase de prueba unitaria correspondiente, utilizando la librería de pruebas junit, asumiendo que ya has cargado dicha librería en tu entorno y que tienes la clase suma en la raíz de tu proyecto, sería la siguiente:
import Suma;
public class MyTest {
@Test
public void probarSuma () {
Suma suma = new Suma(1,2);
assertEquals(3, suma.sumar());
}
}
Si asumimos que la clase Suma es la única clase que tienes en tu entorno, al ejecutar la cobertura de junit, tus pruebas deben cubrir el 100% de la aplicación, puesto que se recorre toda la clase para ser probada. Así también, la ejecución de las pruebas no tienen errores de código (compilación y ejecución).
5. Conclusiones
Las pruebas unitarias son una poderosa herramienta de testing para software y de conocimiento general para desarrolladores de sistemas, puesto que ofrecen una manera mas rápida y fiable que la mayoría de metodologías existentes para pruebas. Por supuesto, existen desde procesos, aproximaciones y metodologías, hasta normas internacionales y modelos de ciclo de vida orientados a pruebas, en donde se centran en la forma mas adecuada de probar software con miras a evitar dependencia de programadores “super heroes” que llegan a salvar el día de un posibles apuros donde la organizaciones no sepan como salir.
En post posteriores profundizaremos mas sobre este tema, y si te gustó el contenido, y consideras aceptable el estar al tanto de las publicaciones, suscríbete a las redes sociales que administramos en el pie de página o registrate para recibir correos acerca de nuevos posts. Así también, si consideras que omitimos algo, o quieres que profundicemos en un tema específico, notifícanos en los comentarios.