lunes, abril 18, 2005

Pruebas Software

En el ciclo de desarrollo de software una de las etapas mas importantes son las pruebas a las piezas de software desarrolladas y luego a los sistemas construídos en base a estas piezas y/o componentes de software.

Un proceso de pruebas de software requiere habitualmente de mucho tiempo y esfuerzo que el desarrollo propiamente tal (alrededor de un 60% del tiempo de desarrollo lo consumen las pruebas), se necesitan metodologías, herramientas y conocimientos adecuados.
Básicamente en este documento se analizaran los siguientes tipos de pruebas:

Caja negra
Cobertura (Caja Blanca)
Aceptación
Rendimiento
Robustez

Cuando se considera terminado un módulo o pieza de software, se realizan las pruebas sistemáticas, inicialmente por los programadores que participaron en el desarrollo, los cuales harán pruebas básicas, para luego entregar el código al equipo de pruebas, el objetivo de estas pruebas es buscar fallas através de un criterio específico, estos criterios se denominan "pruebas de caja negra y de caja blanca".


Las pruebas de caja negra son aquellas que se enfocan directamente en el exterior del módulo, sin importar el código, son pruebas funcionales en las que se trata de encontrar fallas generales y que no estan en el ámbito de su especificación, como ser interfaz con el usuario, apariencia de los menús, control de las teclas, etcétera. Este tipo de pruebas no es aplicable a los módulos que trabajan en forma transparente al usuario, entíendase rutinas y/o procedimientos internos.
Para realizar estas pruebas existe una técnica algebraica llamada "clases de equivalencia", consiste en tratar a todos las posibles entradas y parámetros como un modelo algebraico, y utilizar las clases de este modelo para probar un amplio rango de posibilidades.

Para la generación de estas clases no se puede armar un modelo, pero se pueden seguir las siguientes pautas como guía utilizable para la creación de cada clase. Por ejemplo: Cuando una entrada es booleana, existen solo dos clases, verdadero o falso. Para una entrada que está comprendida dentro de un rango, existen tres clases, por debajo, dentro, y por encima del rango.Utilizando este ejemplo se pueden generar las distintas clases aplicables al módulo en cuestión, luego, se procede a ingresarle al módulo un valor de cada clase.

Las pruebas de caja blanca son mucho mas amplias, normalmente se denominan pruebas de cobertura o pruebas de caja transparente, al total de pruebas se caja blanca se le llama cobertura, la cobertura es un número porcentual que indica cuanto código del programa se ha probado.

Básicamente la idea de pruebas de cobertura consiste en diseñar un plan de pruebas en las cuales se vaya ejecutando sistemáticamente el código hasta que haya corrido todo o la gran mayoría de él, esto que parece complicado, es mas aún cuando el programa contiene código de difícil alcance, como por ejemplo manejadores de errores o "código muerto".

Entiéndase por código muerto a aquellas funciones y/o procedimientos que hemos incluido por encontrarse en librerias pero que no son ejecutadas por el programa directamente. Para los módulos que no poseen condiciones basta con ejecutar una vez el programa para asegurar una cobertura total.Es importante que el diseño de cobertura sea eficiente y lo menos redundante posible, por ejemplo, en el siguiente código:

If Variable_Booleana..Do Modulo_XEndIf

Como no hay un "else", a simple vista con ejecutar una vez con éxito la condición bastaría, en términos de cobertura es así, pero entendiendo que el "Modulo_X" podría modificar variables o valores que afecten a la ejecución del resto del código habría que ejecutar 2 veces la condición, una satisfaciendo y otra no.

Respecto al siguiente ejemplo:

If Variable_Booleana1 .Or. Variable_Booleana2..Do Modulo_XEnd

O este otro:

If Variable_Booleana1 .And. Variable_Booleana2..Do Modulo_XEnd

A simple vista y considerando que ambas variables pueden tener 2 valores se precisarían 4 pruebas para realizar la cobertura, pero esto no es así, solo es necesario 2 pruebas en el caso que el Modulo_X pueda interferir de alguna manera en el programa o una sola satisfaciendo la condición si el Modulo_X no alterara de ninguna manera con el resto de los procedimientos y condiciones a ejecutarse.Probado las 4 posibilidades solo estaríamos probando que funcione el comando "IF" en sí, lo cual ya fue probado por el desarrollador del lenguaje de programación.
Con respecto a la cobertura en bucles (for, while) el tema es un poco mas delicado, a simple vista un bucle no es mas que un salto condicional que se repite hasta que se cumpla o deje de cumplirse una o mas condiciones, en teoría esto es simple, pero en la práctica son una fuente inagotable de versátiles errores, que en su gran mayoría suelen ser catastróficos.

En primer lugar, la cantidad de veces que se ejecute un bucle debe ser precisa, y todos los programadores saben que no es difícil equivocarse y programar un bucle que se ejecute una vez de mas o una vez de menos, siempre que esto suceda los resultados serán indeseables, y muchas veces cuando se trate de manejos de datos complicados de calcular no será fácil advertir el error, el cual será caro cuando se trate de valores que se utilizan para tomar determinaciones a nivel empresarial.

Para realizar la cobertura total de un bucle se necesitan 3 pruebas, cero ejecuciones, una ejecución y mas de una ejecución.

Los bucles de tipo "for", parecerían ser mas sencillos, ya que la cantidad de ejecuciones es definida por su cabecera y controlada por el compilador, con una ejecución bastaría para una cobertura total, siempre y cuando no contengan código que altere el valor de la variable de control o comandos de salida (Exit), en este caso requiere un examen un poco mas detallado ya que el bucle deja de ser responsabilidad del lenguaje compilador y pasa a ser del programador.Particularmente no es aconsejable que se utilicen bucles "for" modificando su variable de control o incluyendo en ellos comandos de salida.

En pocas palabras es muy importante diseñar lo mas precisamente posible las pruebas de cobertura, para que quede en lo posible la mayor parte del código probado con la mínima cantidad de pruebas realizadas.

Hay que tener en cuenta dos puntos importantes, en primer lugar las pruebas de caja blanca no reemplazan, solo complementan a las de caja negra y de aceptación, y en segundo lugar, las pruebas de cobertura deben ser realizadas una ves terminado el software y no deben ser confundidas con las pruebas informales y/o básicas que realiza el programador en momentos de desarrollo, dado que si bien estas van cubriendo distintos fragmentos de cada módulo, nunca son eficaces por no tener un diseño apropiado.

El valor porcentual de pruebas de cobertura de un sistema terminado nunca deberá ser inferior al 51%, y elevándose en función al costo que podría ocasionar las fallas posibles, ascendiendo a un 99% cuando estén involucradas vidas humanas o cuando la falla no da una segunda oportunidad.
El uso de un depurador es muy útil en las pruebas de cobertura, ya que se pueden ir viendo todas las líneas y ejecuciones paso a paso, esto no muy práctico y es bastante tedioso, pero es considerablemente efectivo.

Pruebas de aceptación, son las que hará el cliente, en esta fase de pruebas se determina que el sistema cumple con el objetivo deseado, determina la conformidad del cliente antes de que el programa le sea entregado como una versión final.

Las pruebas conocidas con el nombre de pruebas de rendimiento son aquellas que determinan los tiempos de respuesta, el espacio que ocupa el módulo en disco o en memoria, el flujo de datos que genera a través de un canal de comunicaciones, etc..

Pruebas de transformación, este método curioso y caro aún se pone en funcionamiento por diversas empresas, consiste en dividir el equipo de desarrollo en dos partes una vez realizadas todas las pruebas y corregidos todos los errores, luego una de las dos partes introduce pequeños errores en el sistema y la otra parte debe encontrarlos con los mismos procedimientos que se usaron para buscar los errores nativos. Esto es muy costoso y consume grandes cantidades de tiempo.

Pruebas de robustez, comúnmente denominadas "robustness test" son las encargadas de verificar la capacidad del programa para soportar entradas incorrectas, por ejemplo en un sistema de facturación donde el usuario debe ingresar códigos de productos y luego cantidades es mas que factible que en algún momento ingrese un código en el campo de cantidad, si el programa fue sometido a pruebas de robustez este valor sería rechazado o grabado como una cantidad inmensa pero que no daría error por desbordamiento de datos.

Las denominadas pruebas de resistencia se utilizan para saber hasta donde puede soportar el programa condiciones extremas, por ejemplo los tiempos de respuesta con el procesador a un 95% de su utilidad o con muy poco espacio en disco.

Esta metodología es utilizada por InfoTecnologia en el desarrollo de aplicaciones cliente-servidor y móviles, donde las pruebas resultan ser extremadamente críticas debido a la dinámica que posee la tecnología móvil.

No hay comentarios.: