Dossier sobre el test de software ( y firmware)
Jordi Bartolomé 01-09-2007
Pag 3/3
 
8-Organización del test
8.1-Organización general
Los tests deben basarse en el material generado durante el proceso de desarrollo del programa. Este proceso implica la traducción y transformación de información y es en éste donde se localizan la mayor parte de los malentendidos o errores. El flujo del proceso de desarrollo de la mayoría de metodologías, o ciclos de vida del software, se puede resumir o adaptar al siguiente esquema:
- Las necesidades del cliente son redactadas en el documento de requerimientos.
- Los requerimientos son traducidos en la documentación de objetivos, estableciendo la viabilidad y prioridades del proyecto.
- De los objetivos se extrae la especificación precisa del producto, viéndolo como una caja negra o considerando únicamente su interfaz y las interacciones con el usuario. Es la documentación de la especificación externa.
- En los productos con arquitecturas más complejas, como sistemas de control aereo, sistemas operativos etc. se ha de redactar también el documento de arquitectura del sistema.
- A continuación se extrae el esqueleto del programa, especificando los módulos que lo formaran, cuales serán sus funcionalidades, y como se relacionaran entre ellos.
- Una vez establecidos los módulos, en la documentación de especificaciones se ha de especificar sus funciones e interfaz.

- Finalmente, las especificaciones de los módulos se traducen en el código fuente del programa. Partiendo de que este proceso implica la transformación y adaptación de información y que la mayor parte de los errores tienen lugar al transformar o interpretar esta información, es muy importante tomar algunas medidas:

- Ir con cuidado al elaborar los documentos, atendiendo a lo establecido en cada uno de ellos.
- Hacer una revisión de la documentación previamente elaborada antes de comenzar la redacción de la de la siguiente etapa.
- Orientar las diferentes etapas del test a las diferentes etapas del desarrollo.
La principal ventaja de esta metodología de test es que, a parte de estructurar y ordenar el proceso de test, evita los tests redundantes e improductivos.
 
8.2-Test de desarrollo
Las pruebas de desarrollo son aquellas pruebas que el programador va haciendo mientras desarrolla para verificar que lo que va programando funciona. Normalmente estas son pruebas similares a las de caja blanca que se hacen de forma intuitiva con resultados aceptables. Aún y así puede ser interesante que este aplique alguna técnica concreta de caja blanca.
 
8.3-Test de módulo ( o test de unidad )
Los tests de módulo o tests de unidad son las pruebas de subprogramas, subrutinas o funciones que más adelante se unirán a otras para construir un programa. De esta forma, antes de crear un programa se prueban por separado las unidades que lo formaran. Normalmente se compara el comportamiento de una de estas unidades de orden menor, con el comportamiento definido en las especificaciones con la finalidad de demostrar que, efectivamente, este no las satisface. La ventaja de este tipo de tests es que al trabajar en un contexto acotado, la localización de los errores es mucho más sencilla que si se intentase localizar en el contexto global del programa, y el rendimiento de errores localizados por tiempo invertido es muchísimo mayor.
 
8.3.1-Diseño de casos de test en el test de módulo
A la hora de diseñar los casos de test de un test de módulo es necesario disponer de:
- La especificación del módulo
- Código fuente del módulo

Generalmente estos tests hacen uso de técnicas de caja blanca, ya que al realizarse en contextos más acotados y reducidos es factible utilizar las laboriosas técnicas de caja blanca, cosa que no sucede en un programa completo. No obstante estas se complementan con técnicas de caja negra basadas en las especificaciones.
 
8.3.2-Tipos de tests de integración

Tras haber realizado las pruebas unitarias de los diferentes módulos, será necesario hacer las pruebas de integración. En estas pruebas se ha de intentar reproducir situaciones en que los módulos no funcionen correctamente de forma conjunta, con la intención de validar su funcionamiento como grupo. Se ha de tener en cuenta que al unir los módulos, la probabilidad de fallo del conjunto se incrementa de forma proporcional a la probabilidad de fallo de cada una de las partes, tal como se muestra en el siguiente esquema:

Esquema probabilidad de fallo

Así, es importante realizar este tipo de pruebas para validar el funcionamiento del conjunto. No obstante, a menudo estas pruebas no se pueden realizar de golpe, y se han de ir realizando a medida que los módulos se van desarrollando y probando. En función de esto se plantean diferentes estrategias para la realización de tests de integración. Una opción consiste en desarrollar todos los módulos, testearlos de forma independiente, y finalmente unirlos y probarlos todos juntos. Este tipo de tests se denominan tests de "big bang" o no incrementales. La otra opción consiste en ir probando los módulos a medida que se van desarrollando e integrando al proyecto. Este tipo de tests se denominan tests incrementales.

 
-Tests de integración no incrementales

En los tests de integración no incrementales los módulos del proyecto se prueban de forma aislada. En función de los recursos disponibles, esto se puede hacer en paralelo o de forma secuencial. Como es de suponer muchos de estos módulos necesitaran de otros módulos para funcionar correctamente, para poder realizar las pruebas correctamente se deberán desarrollar "maquetas" de estos. Estos módulos pueden ser de dos tipos: drivers o stubs. Los drivers son módulos hechos para simular el comportamiento de los módulos de orden superior que llaman al testeado. Los stubs son módulos de orden inferior que simulan las funciones que el módulo testeado puede solicitar. Finalmente cuando todos han sido probados se integran y se prueban de nuevo.

Los módulos se desarrollan de forma aislada
Al final los módulos se unen y prueban de forma conjunta
 
-Tests de integración incrementales

En los tests de integración incrementales, los módulos se van testeando a medida que se van desarrollando y añadiendo al proyecto. Así que en estos tests, en lugar de probarse de forma aislada, los módulos se prueban unidos al resto de elementos del proyecto desarrollados hasta el momento. En este punto aparece un problema similar al de los tests no incrementales y es que muy probablemente se tengan que desarrollar maquetas de los módulos necesarios para probar el módulo. No obstante en este tipos de pruebas solo será necesario desarrollar un tipo de módulos de pruebas ( o driver o stubs ) pero no de los dos. Tener que desarrollar drivers, o stubs, dependerá del orden seguido durante el desarrollo. Si se sigue una estrategia de desarrollo bottom-up se deberán desarrollar los módulos driver que simulan los módulos de orden superior. Si se sigue una metodología de tipo top-down, se deberán desarrollar módulos de tipo stub que simulan las funciones o procedimientos de orden inferior.


Bottom-up
El test se inicia por los módulos terminales del programa. Una vez testeados el único criterio para seleccionar el siguiente módulo a testear es que todos sus subordinados hayan sido probados con anterioridad.

Ventajas:
-Es especialmente útil cuando la parte crítica del proyecto se sitúa en los módulos inferiores, ya que como se ha comentado previamente, es aconsejable comenzar a testear los módulos más críticos.
-Las condiciones de test son más sencillas de recrear ya que los módulos drivers son más sencillos que los sutbs. Esto es debido a que normalmente los drivers se limitan a la llamada de determinadas funciones, sin tener que manipular ni retornar muchos datos.
 
Desventajas:
-Se han de crear módulos de tipo driver.
-El programa no existe como elemento presentable hasta el final del proceso.
 
Top-down
Comienza por el módulo principal del programa. A la hora de seleccionar el siguiente módulo a testear el único criterio es que al menos uno de los módulos que lo llama haya sido previamente probado.

Ventajas:
-Es especialmente útil cuando la parte crítica del proyecto se centra en los módulos superiores, ya que como se ha comentado previamente, es aconsejable comenzar a testear siempre los módulos más críticos.
-El programa existe como elemento presentable desde las fases iniciales del proyecto lo que permite hacer demostraciones, revisar factores humanos relacionados con la interfaz y levantar "la moral" de los participantes en el proyecto ya que trabajan con algo muy cercano "en apariencia" al producto final.

Desventajas:
-Se han de crear módulos de tipo stub
-Los módulos de tipo stub son generalmente más difíciles de simular que los de tipo driver ya que es muy difícil simular de forma correcta la respuesta de un módulo que realiza operaciones más o menos complejas.
-Hasta que no se añaden los módulos de entrada salida, la representación de los casos de test y los resultados puede ser compleja. Por ello a parte de los módulos más críticos, es importante añadir antes los módulos de entrada salida.
-Puede ser difícil o imposible crear las condiciones de test debido a la dificultad de dar comportamientos similiares al real a los módulos stub.
 
8.3.4-Tests no incrementales vs. incrementales
Llegados a este punto es interesante remarcar las principales ventajas y desventajas de los métodos incrementales y de los no incrementales. Conocerlas nos permitirá escoger la que se adapte mejor a nuestro proyecto:

a)Técnicas incrementales:
-Las técnicas incrementales requieren invertir menos esfuerzos en el desarrollo de módulos auxiliares, ya que únicamente necesitamos drivers o stubs, pero no los dos simultaneamente.
-Las técnicas incrementales detectan antes los errores de incompatibilidad entre interfazs, ya que se combinan antes, y detectar un antes un error minimiza su impacto.
-Los métodos incrementales facilitan el proceso de detección de errores, ya que al ser un proceso progresivo, cuando se produce un error este se localiza en el último módulo añadido.
-Las técnicas incrementales requieren haber desarrollado y probado aquellos que le preceden en el test, lo que dificulta la paralelización.
 
b)Técnicas no incrementales:
-Los métodos no incrementales requieren invertir más esfuerzos en el desarrollo de módulos auxiliares, ya que los módulos testeados no se ven entre sí hasta el final del proceso y para poderlos probar es necesario desarrollar tanto drivers como stubs.
-Las técnicas no incrementales requieren menos CPU que las incrementales, ya que los módulos se prueban de forma aislada haciendo uso de drivers y stubs los cuales utilizan mucha menos máquina que los módulos reales.
-Los métodos no incrementales facilitan la paralelización del desarrollo ya que no se establece dependencia entre módulos hasta el final del proyecto cuando se unen todos. Esto puede ser especialmente importante en proyectos grandes.
 
8.4-Test de alto nivel
Hasta este punto se han descrito las pruebas de unidad e integración, pero aunque estas hayan sido perfectas, nadie nos garantiza que se hayan encontrado todos los errores ya que, aunque estas hayan sido perfectas, nadie nos garantiza que se hayan encontrado todos los errores ya que estas son incapaces de detectar otros tipos de errores. Los componentes pueden hacer lo que deberían, pero el programa o sistema como conjunto quizás no. Por ello es interesante continuar el test realizando pruebas de más alto nivel que enfoquen el producto desde otra perspectiva, con la intención de localizar errores difíciles de localizar en las pruebas realizadas hasta el momento.
 
8.5-Test funcional
Este tipo de tests se enfoca como una tarea de caja negra ( se confía en las tareas de test previas ) y tiene como finalidad localizar discrepancias entre el programa y las especificaciones externas. Lógicamente, los tests plans usados en estos tests se han de elaborar a partir de las especificaciones externas. Entendiendo las especificaciones externas como una descripción detallada del producto desde la perspectiva del usuario. Por tanto, una persona con un perfil similar al del usuario final puede ser un buen candidato para realizar este tipo de pruebas.
 
8.6-Test de sistema
Bajo este nombre se agrupan variedad de tests que tienen como finalidad comparar el programa o sistema desarrollado, con los objetivos inicialmente planteados para demostrar que no las satisface. En este caso el documento de partida es la documentación de objetivos. No obstante, este tipo de documentos no suele contener descripciones tan precisas de las especificaciones externas. En estos casos una opción interesante suele ser elaborar los casos de test partiendo de la documentación de usuario. En los tests de sistema es aun más aconsejable que ni el desarrollador ni la organización o empresa que crea el producto intervengan en el test. Como se ha dicho con anterioridad, a menudo las organizaciones son las más interesadas en que el test se ejecute lo más rápido posible cumpliendo con los plazos planificados y por ello son las menos "motivadas" en demostrar que un producto no satisface los objetivos planteados. En cuanto al perfil del tester, es importante que este tipo de pruebas las realicen personas con experiencia en el test, y en la áreas implicadas en cada tipo de test. Algunos de estos tests son:

- Tests de volumen (volume testing) : tiene la finalidad de probar que el equipo no puede trabajar con el volumen de datos especificado en los objetivos. Cada programa debe ser puesto en condiciones de carga iguales a las que se encontrará en condiciones de trabajo para localizar errores en él ( bloqueo, relentecimiento etc. )

- Tests de stress (stress testing) : no se debe confundir con los tests de volumen y su finalidad es demostrar que el programa funciona incorrectamente al trabajar con un gran volumen de información en periodos cortos de tiempo de forma repetida. Lógicamente este tipo de pruebas únicamente aplica a productos en que la carga de proceso fluctúa con el tiempo, en aquellos en que el proceso se mantiene constante no tiene sentido realizar este tipo de pruebas. Aunque la mayor parte de las pruebas que se hacen suelen corresponderse con situaciones que se pueden llegar a dar en la realidad, también es muy interesante hacer pruebas en condiciones improbables pero extremas, ya que son estas las que suelen dar más información sobre los puntos débiles del sistema.

- Tests de usabilidad ( usability test): pretende localizar problemas relacionados con el factor humano o con la usabilidad. Un test de usabilidad ha de verificar puntos como:
- Es la interfaz apta para la inteligencia, nivel educativo o condiciones físicas del usuario?
- Son los mensajes entregados por el sistema inútiles, sin sentido o excesivos?
- Es el programa suficientemente claro en lo referente a los mensajes de error, o al contrario es tan poco claro que es necesario un máster de ingeniería para entenderlo?
- Existe integridad conceptual en el sistema de mensajes, es decir, existe algún criterio homogéneo y consistente a la hora de presentar estos al usuario?
- En los puntos críticos, en los que un error puede tener consecuencias importantes, existe suficiente información, o redundancia para evitar que se produzcan estos errores.
- Dispone el programa de mecanismos suficientes para poder recuperarse o deshacer situaciones que una acción indebida requiera?
- Es la interfaz una acumulación desorbitada de opciones que más que ayudar al usuario solo sirven para desorientarlo?
- Da la aplicación suficiente "feedback" al usuario durante la ejecución de acciones? Esto puede evitar malentendidos durante su uso, haciendo pensar a este que la acción se ha ejecutado cuando en realidad no ha sido así, o que el equipo se ha colgado, cuando en realidad este aun está procesando.
- Es el programa fácil de utilizar, o en cambio acaba uno perdido por los menús de opciones sin saber como llegar al punto inicial?

- Test de seguridad ( security test ): tienen como objetivo encontrar vulnerabilidades o agujeros que puedan poner en peligro la seguridad del sistema. Una forma de plantear casos de test para este tipo de pruebas es a partir de vulnerabilidades conocidas en otros sistemas. Este tipo de prubeas son muy importantes en sistemas en los que se manipula información confidencial, el conocimiento de la cual puede tener consecuencias indeseeables, como es el caso de las aplicaciones de comercio electrónico.

- Test de rendimiento ( performance test ): muchos programas tienen dentro de sus objetivos hitos de rendimiento o eficiencia, como puede ser tiempo de respuesta, o niveles de "throughput".

- Test de configuración ( configuration test ) : la finalidad de estos tests es demostrar que el sistema de configuración que adapta la aplicación al entorno de usuario ( sistema operativo, bases de datos, dispositivos hardware etc.) presenta deficiencias o no funciona correctamente. Obviamente el número de combinaciones es muy grande, pero como mínimo el programa debería ser probado en un entorno que representase el entorno más simple posible, y otro que representase al más complejo posible.

- Tests de compatibilidad (compatibility/converision testing) : a menudo los programas que se desarrollan tienen como finalidad reemplazar a otros que han de trabajar junto a otros sistemas. En estos casos es necesario hacer pruebas que demuestren que el programa se integra bien con otros ficheros o equipos en que ha de trabajar.

- Test de instalación: es un tipo de test poco frecuente ya que la finalidad de este no es encontrar errores en el programa en sí, sino en el proceso de instalación. En este se han de considerar aspectos vistos en tests anteriores y se ha de tener en cuenta que:
- El usuario probablemente tenga que seleccionar entre un grupo de opciones.
- Serán necesarios ficheros y librerías que después se deberán copiar en el ordenador destino.
- Ha de existir hardware válido para poder hacer la instalación.
- Posiblemente se necesaria conexión a la red.

Este tipo de pruebas puede ser más crítico de lo que se piensa ya que la instalación es la primera experiencia que el usuario tiene con la aplicación, y si esta es muy complicada o accidentada puede hacer que el usario la rechace, y busque otra alternativa más sencilla, o simplemente tenga poca confianza en ella. En la instalación se puede aplicar aquello de que "los primeros minutos son los que importan".

- Tests de recuperación (recovery testing): algunos programas a menudo tienen objetivos de recuperación que especifican como éste se ha de recuperar de posibles errores de programación, de errores en los datos o el hardware ( p.ej excepciones ). En estas pruebas se han de establecer casos de test que pongan a prueba estas condiciones de recuperación. Incluso en ocasiones los objetivos establecen unos límites de tiempo en la recuperación del sistema ( Main Time to Recovery ). Se ha de intentar demostrar que no se cumplen estos tiempos.

- Test de soporte y mantenimiento (serviceability test): con frecuencia muchos productos se plantean con la finalidad de dar ayuda al usuario y ser actualizados y mantenidos de forma sencilla. Pero se ha de verificar que ello realmente es así, y de si este dispone de los mecanismos necesarios para realizar estas tareas.

- Tests de documentación (documentation testing): la documentación debe ser también sometida a un proceso de revisión verificando su claridad y precisión.

- Tests de idioma (language testing): es posible que la traducción del software a otro idioma implique modificaciones en el comportamiento de este, o que algunos mensajes pasen a mostrarse de forma incorrecta... Por ello al hacer traducciones es interesante realizar pruebas de idioma, para garantizar que este se encuentra bien traducido al idioma y sin errores.

 
8.7-Test de aceptación
Es el proceso consistente en comparar el programa obtenido con los requerimientos iniciales y con las necesidades del usuario. La principal diferencia de este test con los citados hasta este punto, es que este lo realiza el cliente o usuario final con el producto terminado. Es decir, es el cliente quien, durante un periodo pactado, ha de intentar demostrar que el producto no cumple los requerimientos. Esto lo hace comparando el funcionamiento del programa con lo establecido en el contrato. Si no lo consigue el producto se da por aceptado.
 
9-Técnicas de test de relectura de código, o técnicas “humanas”
En los inicios de la informática los programadores partían de la idea de que al programar había suficiente con que los ordenadores entendiesen el código. Más tarde, a inicios de los 70, cuando muchos proyectos que se iniciaron en los 70 tuvieron que ser retomados por una nueva generación de técnicos, se vio la importancia de comentar y estructurar correctamente el código para facilitar su comprensión. En este punto se vio también la utilidad de la relectura de código como proceso de test, técnica que hoy es ampliamente utilizada. Estas técnicas también se denominan humanas, ya que en ellas no se encuentra implicada ninguna máquina, simplemente un equipo de personas ajeno al desarrollo, que revisa las líneas de código. En todos estos métodos existe un moderador. El moderador ha de ser un programador con experiencia que no haya participado en el desarrollo del producto. Las funciones de éste son:
- Distribuir el material necesario para preparar la sesión y planificar las fechas.
- Dirigir la sesión
- Tomar nota de los errores
- Comprobar que los errores encontrados realmente se acaben solucionando.

Las técnicas de relectura de código tienen algunas ventajas y desventajas:
- Cuando se encuentra un error este es localizado de forma precisa en el código, facilitando la generación de una lista con la localización precisa de los errores para su posterior corrección.
- El rendimiento de este tipo de técnicas es del 30% al 70% de errores lógicos y de programación, no obstante da unos resultados pobres en la localización de errores de diseño, ya que se centra mucho en el código, perdiendo quizás la visión global de la ubicación y funcionamiento del producto.
- Los errores encontrados con estas técnicas suelen ser errores más sencillos " visibles" por la mente humana, y a menudo no permite localizar los errores más complejos detectables solo por la ejecución de una máquina.
- Requieren una buena planificación y consumen muchos recursos humanos. Normalmente estas sesiones solo van orientadas a la detección de errores pero si se cree conveniente también se pueden corregir. Si el moderador considera que hay más errores de lo normal, puede convocar una nueva sesión para revisar de nuevo el código corregido. Las sesiones deberían durar como mucho de 90 a 120 minutos, ya que el rendimiento de los participantes baja mucho a partir de ese tiempo, convirtiéndose en reuniones improductivas. Lógicamente los programas "grandes" deberán ser revisados en varias sesiones.

En este tipo de tests la actitud de los participantes es crítica, ya que si el programador ve el proceso como un ataque a su trabajo, a parte de crearse un mal ambiente de trabajo, tomará una actitud defensiva que dificultará el proceso. Debemos recordar que todos cometemos errores al programar. Por otro lado el programador también ha de procurar evitar tomar una actitud "orgullosa" sobre su trabajo y facilitar al máximo el trabajo a sus compañeros.
 
9.1-Técnica “Code Inspection”
Intervienen 4 personas: el moderador, el programador, el diseñador ( si no lo es el programador ) y un especialista en técnicas de test.
El moderador distribuye a los participantes el código a revisar varios días antes, para que puedan familiarizarse con él. También les proporciona las especificaciones de diseño y los puntos críticos que pretende abordar en la sesión. Los participantes deberán revisar el código fuente teniendo en cuenta los puntos críticos. Cuando tiene lugar la sesión:
- El programador describe, sentencia a sentencia la lógica del programa, mientras que los participantes le van haciendo preguntas sobre el código y comentarios sobre la posible existencia de errores. Con frecuencia es el propio programador quien detecta los errores en su propio código al releerlo con más calma.
- A medida que se va avanzando en el código, se va revisando el "checklist" de localización de errores.
 
9.2-Técnica “Code WalkThorugh”
Intervienen de 3 a 5 participantes: el moderador, un tester y una cuarta persona. Esta cuarta persona puede ser un programador con experiencia, un experto en el lenguaje, la persona encargada de mantener el producto o incluso un programador novel para dar una nueva perspectiva a la revisión. En esta técnica es el secretario quien toma nota de los errores hallados y no el moderador. Varios días antes, el moderador o secretario, distribuye a los participantes el código a revisar para que puedan familiarizarse con él. También les proporciona las especificaciones del diseño. El tester deberá revisar el código y las especificaciones, y elaborar una lista de casos de test simples, estableciendo un conjunto de entradas y salidas esperados para estos. Durante la sesión el tester expondrá los casos de test que ha planteado y los participantes deberán recorrer mentalmente y por separado, la lógica del programa verificando que esta da como resultado el valor esperado.
 
9.3-Desk checking
Es una técnica menos costosa en cuanto a recursos, y equivale a aplicar técnicas de relectura (code Walkthorugh o code Inspection) pero de forma individual, es decir que es similar a las técnicas anteriores, pero aplicadas por una única persona. Es mucho menos eficaz que las descritas hasta ahora, pero mejor esto que nada. Lógicamente los mejores resultados se obtienen cuando la persona implicada en el test no ha intervenido de forma directa en el desarrollo. Aun y así, este tipo de pruebas son de mucha utilidad al principio, cuando las hace el propio programador en tiempo de desarrollo ( pruebas de desarrollo ) con la intención de verificar que el código que está generando hace lo que realmente esperaba. Es decir es un técnica muy adecuada como test de desarrollo.
 
9.4-Peer rating
Esta técnica no es bien una técnica de test de código, pero está relacionada con este tipo de técnicas. El objetivo del Peer Rating, no es localizar errores lógicos, sino errores de forma. Es decir, pretende verificar la calidad, sostenibilidad, modularidad, "ampliabilidad", usabilidad y claridad del código generado. Pretende ser una herramienta de evaluación del programador, y puede ser incluso él mismo el promotor de este tipo de pruebas para hacer-se una autoevaluación. Sea quien sea el responsable, ha de enviar a un grupo de 6 a 20 personas ( para garantizar el anonimato ) dos módulos o fragmentos de código. Uno ha de ser representativo de su mejor trabajo, y el otro representativo de su peor trabajo. Los supervisores han de responder de forma anónima ( p.ej con un formulario impreso ) a preguntas del estilo:
-¿Es el programa fácil de entender.
-¿Es el diseño de alto nivel razonable y visible?
-¿Es el diseño de bajo nivel razonable y visible?
-¿Estaba correctamente documentado?
-¿Sería fácil modificar este programa?
-¿Estarías orgulloso de ser el autor de este código?

Finalmente los resultados se evaluaran de forma estadística tomando especial atención a aquellos puntos u observaciones aparecidas con más frecuencia en los formularios. Para evitar diversidad de criterios, es importante, que los participantes evalúen usando criterios comunes, como p.ej los establecidos en la hoja de estilos u otros estándares.

 
     Página anterior (pag 2/3)   Volver al Índice  

Regresar al índice de documentos