Appearance
Unidad 3: Pruebas
En el desarrollo de software, es importante incluir pruebas que nos permitan detectar errores de forma temprana y asegurarnos de que nuestros algoritmos o programas estén funcionando correctamente, cumpliendo con las especificaciones y produciendo los resultados esperados. Las pruebas son una parte integral del proceso de desarrollo y deben ser consideradas y escritas junto con el código.
Pruebas de Software
Llevar a cabo pruebas, o testing en inglés, es una tarea esencial en el desarrollo de software, ya que permite asegurarnos de que nuestros programas funcionen correctamente, incluso con el paso del tiempo o con cambios en el código. Además, cuando el programa se vuelve más complejo o varias personas se involucran en su desarrollo, las pruebas ayudan a garantizar que las nuevas modificaciones no afecten a las partes antiguas del programa.
La verificación consiste en ejecutar el algoritmo o programa con una amplia variedad de conjuntos de datos de entrada, con el objetivo de detectar posibles errores (o bugs en inglés) y corregirlos. Esta tarea también se conoce como depuración (o debugging en inglés).
Tipos de Errores
Cuando un programa se ejecuta, pueden suceder tres tipos de errores:
Errores de compilación

Se producen por un uso incorrecto de las reglas del lenguaje de programación y normalmente suelen ser errores de sintaxis. En estos casos, la computadora no puede comprender la instrucción, debido a que está mal escrita, por lo tanto, la ejecución se detiene y se imprime la lista de errores que se encontraron durante la compilación.
Errores de ejecución

Se producen por instrucciones que la computadora puede comprender, pero no ejecutar. Por ejemplo, el más común de ellos es la división por cero. En estos casos, se detiene la ejecución y se imprime un mensaje de error.
Errores lógicos

Se producen en la lógica del programa y usualmente están asociados a errores del diseño del algoritmo. Son los más difíciles de detectar, ya que la computadora puede ejecutar el programa sin errores de compilación ni de ejecución, y, sin embargo, no obtener el resultado esperado. Cuando ocurren, es necesario volver a la fase de diseño del algoritmo, modificar el algoritmo, actualizar el programa fuente, compilarlo y ejecutarlo nuevamente.
Tipos de pruebas
Existen distintos tipos de pruebas, las cuales se pueden clasificar de acuerdo a su enfoque y a su nivel de detalle. En general, las pruebas se pueden clasificar en dos grandes grupos:
Pruebas estructurales o de caja blanca

Las pruebas de caja blanca se realizan sobre los detalles procedimentales del código a evaluar, por lo que es necesario conocer el código fuente del programa. El caso más común de este tipo de pruebas son las Pruebas Unitarias, que comprueban el comportamiento de las funciones tomándolas como una unidad aislada del resto del programa.
Por ejemplo, supongamos que estamos escribiendo un programa para calcular el área de un círculo. Para hacer esto, hemos escrito una función llamada calcularAreaCirculo(radio):
esjs
funcion calcularAreaCirculo(radio) {
return Mate.PI * radio * radio;
}Para probar que nuestra funcion funciona correctamente, podemos escribir una prueba unitaria que, para un un radio determinado, afirme que la función devuelve el valor esperado. Para esto, podemos utilizar la librería de pruebas para EsJS, @es-js/prueba:
En este caso, el caso de prueba se llama 'calcula el área de un círculo de radio=2' y se ejecuta la función calcularAreaCirculo con un radio de 2. Luego, se verifica que el resultado de la función sea igual a 12.566370614359172 utilizando la función afirmarIguales de la librería de pruebas.
Podemos agregar más casos de prueba para verificar que la función funciona correctamente para otros valores de radio. Por ejemplo, podemos agregar un caso de prueba para un radio de 0:
Otros casos de prueba que podríamos agregar son:
radionegativoradiodecimalradiomuy granderadiomuy pequeñoradioinfinitoradiode tipo no numéricoradioindefinidoradionulo
Pruebas funcionales o de caja negra

Este tipo de pruebas se realizan sobre las entradas y salidas del programa, es decir, su interfaz. Para ello no es necesario conocer el código fuente del programa, pero si los requisitos funcionales que el programa debe cumplir. De manera que, dado un conjunto de datos de entradas, se ejecuta el programa y se observan los resultados de salida enfocándose en el qué hace y no en el cómo lo hace.
Por ejemplo, herramientas como Cypress nos permiten escribir pruebas funcionales para un sitio web. Para esto, Cypress simula el comportamiento de un Usuario real, como por ejemplo, hacer clic en un botón, escribir texto en un campo de texto, etc. De esta manera, podríamos probar que un formulario de registro de usuarios funciona correctamente, y efectivamente crea un usuario en la base de datos.
Lectura complementaria: Desarrollo dirigido por pruebas
El desarrollo dirigido por pruebas, o Test Driven Development (TDD) en inglés, es una técnica de diseño e implementación de software que consiste en desarrollar las distintas partes de nuestro programa efectuando tres pasos:
- Escribir el caso de prueba que queremos que nuestra función realice.
- Escribir el código de la función hasta que pase la prueba.
- Refactorizar el código para mejorarlo progresivamente.
Para profundizar sobre TDD, leer el libro Diseño Ágil con TDD de Carlos Blé, Capítulo 2.1 (páginas 48 a 55).
Pruebas unitarias
Para probar nuestros programas, utilizaremos la librería @es-js/prueba, de la cual importaremos la función pruebas y la función afirmarIguales:
esjs
importar { pruebas, afirmarIguales } desde '@es-js/prueba'La función pruebas recibe un objeto con los casos de prueba que queremos ejecutar. Cada caso de prueba es una propiedad del objeto, y su valor es una función que ejecutará el caso de prueba. Dentro de la función, podemos ejecutar el código que queremos probar y luego verificar que el resultado sea el esperado utilizando la función afirmarIguales.
La función afirmarIguales recibe dos parámetros: el valor esperado y el valor obtenido. Si los valores son iguales, la prueba pasa, de lo contrario, la prueba falla.
