11

Click here to load reader

Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

Embed Size (px)

Citation preview

Page 1: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

Técnicas para diseñar casos de prueba del software Carlos Núñez Lay

RESUMEN

Dada la actual ubicuidad del software, un mal funcionamiento del mismo puede ocasionar desde la molestia por un mensaje inapropiado, hasta la pérdida de cuantiosas sumas de dinero o, peor aún, de vidas humanas. Por ello, el software, a semejanza de cualquier artefacto tangible, debe ser sometido a pruebas para evaluar si cumple adecuadamente con lo que se espera de él. Aunque el desarrollador de software realiza pruebas del mismo, estas –aún en empresas con personal dedicado a esta actividad específica- se efectúan de manera intuitiva e informal. Dada la creciente demanda de software de calidad, la prueba o “testeo” del software en una actividad que ha evolucionado con el uso de diversas técnicas y herramientas que la alejan del arte y la acercan a la ingeniería.

En las siguientes secciones se presentan los conceptos fundamentales de la prueba del software y se revisan algunas técnicas para diseñar casos de pruebas. Dentro del conjunto de estas técnicas se han escogido las referidas a las pruebas unitarias del código ejecutable, tanto desde un enfoque funcional (“caja negra”), como desde un enfoque estructural (“caja transparente” o “caja blanca”). Aunque también son importantes para la calidad del software, no son motivo de este artículo las pruebas estáticas, tales como las inspecciones grupales del código, o la revisión de programas por los colegas.

1. INTRODUCCIÓN

Según la IEEE, probar el software es analizarlo para detectar diferencias entre las condiciones existentes y las requeridas, y para evaluar las características del mismo.

Obsérvese que -según esta definición- probar el software no consiste en mostrar que el software realiza las funciones requeridas (“que funcione”). Por el contrario, se debe partir de la suposición de que el software contiene defectos y de que la prueba se realiza para detectar la mayor cantidad posible de estos y – en consecuencia – aumentar su confiabilidad y su calidad. El trabajo de probar software consiste –entonces- en diseñar casos de prueba, llevarlos a cabo en un entorno controlado, detectar defectos, documentarlos y reportarlos.

Dado que usualmente se tienen limitaciones de tiempo y recursos, el número de casos de prueba debe ser finito y, por tanto, lo más eficientes posibles, es decir, que tenga una alta probabilidad de encontrar defectos. Probar todos los casos posibles puede resultar imposible, mientras que hacerlo con casos elegidos aleatoriamente encierra una alta probabilidad de no detectar defectos.

En este artículo se describen algunas técnicas para diseñar casos de prueba del código ejecutable a nivel unitario. En la secciones siguientes se enumeran los principios que deben guiar este tipo de pruebas y las dos clases de técnicas que nos permiten diseñar casos de prueba eficientes: de caja negra o funcionales y de caja transparente (o blanca) o estructurales.

Page 2: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

2. PRINCIPIOS DE LA PRUEBA DEL SOFTWARE

Estos principios son importantes porque guiarán el accionar del profesional que prueba del software. Ilene Burstein señala los siguientes, reformulando los establecidos originalmente por Glenford J. Myers:

Principio 1

Probar es el proceso que consiste en ejecutar un componente de software utilizando un conjunto de casos de prueba previamente seleccionados con la intención de detectar defectos y de evaluar su calidad.

Esto supone separar las pruebas de la depuración o “debugging”, actividad esta que se refiere a reparar el software eliminando los defectos.

Principio 2

Un buen caso de prueba es aquel que tiene una alta probabilidad de hallar defectos aún no detectados.

Partiendo de la hipótesis de la presencia de un determinado tipo de defecto, se escogen las condiciones de entrada, se determinan los resultados esperados y se realiza la prueba para determinar si el defecto está o no presente.

Principio 3

Los resultados de cada prueba deben ser revisados meticulosamente.

Si un defecto es pasado por alto o si se declara –equivocadamente- la existencia de un defecto que no es tal, las consecuencias pueden ser muy costosas.

Principio 4

Cada caso de prueba debe incluir el resultado esperado.

El resultado esperado es lo que permitirá determinar si existen o no defectos.

Principio 5

Los casos de prueba deben incluir condiciones de entrada válidas e inválidas.

La robustez del software se puede evaluar probando su funcionamiento con entradas inválidas.

Principio 6

La probabilidad de que existan defectos adicionales en un componente de software es directamente proporcional al número de defectos ya detectados en ese componente.

Este principio se basa en la evidencia empírica. Las razones pueden ser el nivel de complejidad o algunos defectos de diseño.

Principio 7

Page 3: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

Las pruebas deben ser conducidas por personas independientes a las que hicieron el desarrollo.

El desarrollador está síquicamente preparado para que su obra funcione “bien”, de modo que le será muy difícil asumir el principio 1: detectar defectos.

Principio 8

Las pruebas deben ser repetibles y reutilizables.

Las pruebas deben ser repetidas luego de haberse reparado el defecto. Además también serán muy útiles para las pruebas de regresión, es decir, las que se realizarán cuando, por razones de evolución o mejora, el software tenga que ser modificado.

3. TÉCNICAS DE CAJA NEGRA

El término “Caja Negra” se refiere a que con este enfoque se deja de lado la estructura interna del software, es decir, solo se toma en cuenta qué hace (o debe hacer) el software, mas no el cómo lo hace. La materia prima para estas técnicas puede ser la descripción funcional del software, las condiciones de entrada y de salida, o un diagrama Entrada-Proceso-Salida bien especificado.

Las técnicas de Caja Negra permiten revelar defectos y/o ambigüedades en los requerimientos y en las especificaciones del software.

3.1. Particiones de Equivalencia

En esta técnica, el dominio de datos de entrada es particionado en una cantidad finita de clases de equivalencia (válidas e inválidas). Cualquier dato miembro de una clase de equivalencia será un elemento representativo de dicha clase y permitirá obtener información (revelar defectos) acerca del comportamiento del software con los datos de esa clase de equivalencia. Realizar pruebas para todas y cada una de estas clases de equivalencia permite superar la necesidad de probar exhaustivamente todos los posibles datos de entrada, lo cual generalmente es imposible.

¿Cómo se identifican las clases de equivalencia?

El proceso de identificación de las clases de equivalencia es un proceso heurístico que se basa –usualmente- en la descripción de los datos de entrada que encontramos en las especificaciones del software.

Glenford J. Myers menciona algunas pautas para identificar clases de equivalencia:

1. ‘‘Si una condición especifica un rango de valores, se identifican una clase de equivalencia válida y dos clases de equivalencia inválidas”

Por ejemplo: CANTIDAD puede ser un valor entre 1 y 999. La clase de equivalencia válida será 1 ≤ CANTIDAD ≤ 999. Una clase inválida será CANTIDAD < 1, y otra clase inválida: CANTIDAD > 999.

2. ‘‘Si una condición especifica una cantidad de valores, se identifican una clase de equivalencia válida y dos inválidas”

Page 4: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

Por ejemplo: se pueden listar de 1 a 6 propietarios de un bien. La clase de equivalencia válida será de 1 a 6 propietarios, mientras que las dos inválidas serán: sin propietario y más de 6 propietarios.

3. ‘‘Si una condición especifica un conjunto de valores válidos, se identifican una clase de equivalencia válida y una clase inválida”

Por ejemplo: el tipo de vehículo puede ser BUS, MICROBUS, CAMIÓN, o AUTO. Se tendrán cuatro clases de equivalencia válidas (los cuatro valores válidos) y una inválida (cualquier valor no especificado, digamos “VOLQUETE”)

4. ‘‘Si una condición se especifica como debe ser , se identifican una clase de equivalencia válida y una inválida”.

Por ejemplo: el primer carácter de un código debe ser una letra. La clase de equivalencia válida será: es una letra; y la clase inválida: no es una letra.

5. ‘‘Si tiene motivos para pensar que el software no manipula de manera similar a todos los elementos de una clase de equivalencia, entonces particiónela en clases de equivalencia más pequeñas’’

Luego de identificar las clases de equivalencia, se deberá proceder a escribir cada caso de prueba tratando que este cubra la mayor cantidad de clases de equivalencia válidas, hasta que todas hayan sido consideradas. Por el contrario, cada clase de equivalencia inválida deberá ser cubierta por un caso de prueba de manera individual, hasta que todas sean cubiertas.

Consideremos el ejemplo del ingreso a una base de datos de un código de artículo con las características siguientes:

o Está compuesto por caracteres alfanuméricos

o El número de caracteres varía entre 4 y 8

o El primer carácter debe ser una letra

Las clases de equivalencia (CE) podrían ser:

o CE1 - El código ingresado es alfanumérico

o CE2 - El código ingresado NO es alfanumérico

o CE3 - El código ingresado tiene entre 4 y 8 caracteres

o CE4 - El código ingresado tienen menos de 4 caracteres

o CE5 - El código ingresado tiene más de 8 caracteres

o CE6 - El primer carácter es una letra

o CE7 - El primer carácter NO es una letra

Los casos de prueba para cubrir las clases de equivalencia identificadas podrían ser:

Dato de prueba Clases de equivalencia válidas

Clases de equivalencia

inválidas

Page 5: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

ABC123 CE1, CE3, CE6

AB*123 CE2

A CE4

ABCDEF123456 CE5

123ABC CE7

3.2. Análisis de Valores Límites

Esta técnica es un complemento de la anterior. Los valores límite son aquellos que se encuentran en los “bordes” de las clases de equivalencia. La experiencia muestra que muchos errores ocurren en el tratamiento a estos valores límite.

Nuevamente Glenford J. Myers aporta algunos lineamientos para hacer este análisis:

1. ‘‘Si una condición especifica un rango de valores, desarrolle casos de prueba para los extremos del rango y para valores que estén inmediatamente debajo y encima de los extremos inferior y superior del rango”

Para el antes mencionado ejemplo de la CANTIDAD -que puede ser un valor entre 1 y 999- deberían considerarse casos de prueba para los valores 1 y 999, así como para 0 y 1000.

Si se tratara de una LONGITUD con un rango entre 5.0000 y 10.0000, tendríamos que considerar casos de prueba para los valores 5.0000, 10.0000, 4.9999 y 10.0001.

2. ‘‘Si se especifica un conjunto ordenado, tal como una lista o una tabla, se debe tener especial cuidado en el primer elemento del conjunto, y en el último”

Si consideramos el ejemplo del ingreso de un código de artículo, encontramos valores límites en la longitud del código (de 4 a 8 caracteres). En base a ello podríamos añadir los casos de prueba siguientes:

Dato de prueba Valores límite

AB1 3

AB12 4

ABCD1234 8

ABCD12345 9

3.3. Gráficos causa-efecto

Una debilidad de la técnica de las técnicas de particiones de equivalencia y análisis de valores límite es que no facilita la combinación de condiciones. Los

Page 6: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

gráficos causa-efecto permiten combinar condiciones, lo cual también ayuda en el hallazgo de ambigüedades y/o inconsistencias en las especificaciones.

Esta técnica es una adaptación de aquella utilizada para probar circuitos lógicos digitales. En esta técnica las especificaciones del software -dadas en un lenguaje natural- se modelan en un lenguaje formal: los gráficos causa-efecto. Para ello, a partir de cada especificación del software deben identificarse:

o las causas – condiciones de entrada o clases de equivalencia de entrada

o los efectos – condiciones de salida o transformaciones observables

o las restricciones – limitaciones externas del software

Con estos elementos se construye un gráfico booleano:

o las causas y los efectos son los nodos del gráfico

o las causas se ubican a la izquierda del gráfico, y los efectos a la derecha

o las relaciones lógicas entre causas y efectos se grafican con vectores y utilizando los operadores lógicos AND, OR y NOT

Los símbolos básicos para los gráficos causa efecto son los siguientes:

Luego, el gráfico es vaciado a una tabla de decisión que servirá para desarrollar los casos de prueba necesarios. Cada causa y cada efecto tendrán una fila en la tabla. Cada columna de la tabla representará una combinación de causas y corresponderá a un caso de prueba.

Tomemos como ejemplo la especificación de un módulo para buscar un carácter en una cadena: se debe ingresar la longitud de la cadena y el carácter a buscar. Si la longitud de la cadena es mayor a 80 debe mostrarse un mensaje de error. Si el carácter se encuentra en la cadena, debe mostrarse su posición, de lo contrario debe mostrarse el mensaje “No encontrado”.

Page 7: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

Las causas o condiciones de entrada serían:

C1: entero positivo entre 1 y 80 C2: carácter a buscar

Los efectos o condiciones de salida serían:

E1: Longitud fuera de rango E2: Posición del carácter E3: Carácter no encontrado

El gráfico causa-efecto para esta especificación, y las proposiciones que representa sería las siguientes:

• Si C1 y C2, entonces E2

• Si C1 y no C2, entonces E3

• Si no C1, entonces E1

El paso siguiente es vaciar el gráfico en la tabla de decisión siguiendo el procedimiento siguiente para cada efecto (“1” representa la presencia de la causa o efecto, “0” representa su ausencia, y “-“ indica que no se considera):

o Seleccione un efecto

o Retroceda a través del gráfico y encuentre todas las combinaciones de causas que hagan que el efecto ocurra

o Cree una columna en la tabla de decisión para cada combinación de causas

o Determine, para cada combinación, los estados de los demás efectos y colóquelos en la columna

Para este sencillo ejemplo, la tabla de decisión sería la siguiente:

Prueba 1 Prueba 2 Prueba 3

C1 1 1 0

C2 1 0 -

E1 0 0 1

E2 1 0 0

Page 8: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

E3 0 1 0

3.4. Conjetura de errores

Esta técnica consiste en que la(s) persona(s) que diseñan los casos de prueba enumere posibles errores, en base a su experiencia e –incluso- su intuición. Es un proceso ad-hoc, por lo que no hay un procedimiento establecido para hacer conjeturas. Sin embargo, si se tienen documentados los defectos de las versiones anteriores, o de programas similares, esta documentación será una fuente muy valiosa para enriquecer la conjetura de errores.

Ejemplos típicos son los casos en que puede ocurrir una división entre cero, la manipulación de arreglos y de punteros más allá de sus límites, o las condiciones del entorno del software.

4. TECNICAS DE CAJA TRANSPARENTE

Al contrario del enfoque de Caja Negra, en este caso las técnicas se basan en el conocimiento de la estructura interna del software. El objetivo es asegurar que los componentes del programa están trabajando adecuadamente, por lo que se debe conocer el código o el seudo código del software para forzar la ejecución de alternativas específicas del software (bifurcaciones, por ejemplo),

Éstas técnicas son útiles para revelar defectos de lógica, control de condiciones, secuenciación e inicializaciones.

4.1. Cobertura lógica

Al analizar la estructura lógica interna –aún de programas relativamente sencillos- nos damos cuenta que el número de las posibles secuencias lógicas de ejecución es muy grande, lo cual hace –nuevamente- materialmente imposible realizar pruebas exhaustivas que cubran todas las posibilidades. Por ello, se requiere un criterio para determinar cuántos casos de prueba serán necesarios para considerar que el software ha sido suficientemente probado. Este criterio se le conoce como criterio de cobertura.

El criterio de cobertura más simple e intuitivo podría ser: diseñar los casos de prueba necesarios para que se ejecute por lo menos una vez cada sentencia del programa. Pero para un programa como el del código mostrado, este criterio es muy débil. Basaría con hacer a = 2, b = 0 y x = 3 para cumplir con este criterio. Sin embargo, podrían pasarse por alto defectos en el sentido de los operadores lógicos al codificar x < 1 en vez de x > 1, por ejemplo.

public void foo (int a, int b, int x) { if (a > 1 && b == 0) {

x = x / a; } if (a == 2 || x > 1) {

x = x + 1; }

}

Un criterio de cobertura bastante completo es el denominado Cobertura de Condición Múltiple que señala que deben diseñarse los casos de prueba necesarios para que se invoquen por lo menos una vez cada una de las

Page 9: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

combinaciones posibles de los resultados de condición en cada decisión. Y si se trata de programas con múltiples puntos de entrada, habría que agregar y que se invoquen por lo menos una vez cada uno de los puntos de entrada.

Por ejemplo, para probar el programa anterior de manera adecuada se deberían considerar ocho combinaciones:

1. a > 1, b = 0 5. a = 2, x > 1

2. a > 1, b ≠ 0 6. a = 2, x ≤ 1

3. a ≤ 1, b = 0 7. a ≠ 2, x > 1

4. a ≤ 1, b ≠ 0 8. a ≠ 2, x ≤ 1

En este ejemplo, las ocho combinaciones podrían ser cubiertas con cuatro casos de prueba:

1. a = 2, b = 0, x = 4

2. a = 2, b = 1, x= 1

3. a = 1, b = 0, x = 2

4. a = 1, b = 1, x = 1

4.2. Flujo de datos

Esta técnica se basa en el rol de las variables dentro del programa y es útil para detectar defectos debido a la definición, inicialización y/o uso de las mismas. Por su naturaleza, la eficacia de esta técnica decae conforme el tamaño del programa aumenta, por lo que se recomienda para programas pequeños y complejos.

Las variables de un programa pueden jugar diferentes roles en determinadas sentencias: se les puede asignar un valor como en read x, o en x = y + 10; pueden usarse como un predicado como en if x > 100; o para hacer un cálculo como en y = 25 * x. A las sentencias de asignación se les denominará de definición (def), mientras que a las otras se les denominará de uso (uso)

Esta técnica trata de analizar el flujo de datos desde las sentencias de asignación hasta aquellas donde se usan las variables. Para ello se debe identificar y clasificar las ocurrencias de cada variable, ya que durante las pruebas se deben ejecutar todas las asignaciones y todos los usos.

En el ejemplo siguiente se tienen cuatro variables cuenta, i, n y numero.

1 cuenta = 0 2 read (n) 3 i = 1 4 while (i <= n) 5 read (numero) 6 cuenta = cuenta + 1

Page 10: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

7 i = i + 1 8 end while 9 print (cuenta)

El siguiente paso es tabular las ocurrencias de definición y uso de cada variable. En las tablas siguientes se especifica la línea de código en la que aparece la variable y un número secuencial para cada flujo. Las variables podrían ser definidas y usadas en la misma sentencia.

cuenta i n numero

def uso def uso def uso def uso 1 1 6 5 3 4 9 2 4 10 5 6 2 1 9 6 3 7 3 6 5 7 7 7 4 6 9 8 7 4

Luego deben generarse los datos de prueba para ejecutar todos los flujos tabulados. Para este ejemplo bastarían dos casos de prueba:

Datos de prueba Flujos

n = 0 2, 5, 9 n = 3; numero =1,2,3 1, 3, 4, 5, 6, 7, 8, 9, 10

4.3. Prueba de lazos (loops)

Los lazos o “loops” son estructuras de programación a las que frecuentemente están asociados diversos defectos del software, por lo que merecen una especial atención.

Para un lazo simple que puede variar de cero a n iteraciones, se deben considerar casos de prueba para:

o Cero iteraciones (el lazo no se ejecuta)

o Una iteración

o Dos iteraciones

o k iteraciones (k < n)

o n – 1 iteraciones

o n + 1 iteraciones (si es posible)

o Valor negativo para la variable de control del lazo

Si el mínimo de iteraciones fuera mayor a cero, pruebe con un número de iteraciones menor al mínimo.

Para los lazos anidados los casos de prueba pueden crecer exponencialmente. Para limitar este número de casos considere lo siguiente:

o Empiece con el nivel más interno, poniendo los niveles externos en sus valores mínimos.

o Pruebe el mínimo, el mínimo + 1, un número típico, el máximo – 1 y el máximo número de iteraciones para el nivel más interno.

Page 11: Tecnicas para diseñar casos de prueba del Software - Carlos Nuñez

o Suba un nivel, establezca un número típico de iteraciones para el nivel interno, repita el paso anterior para el presente nivel, manteniendo los niveles externos en sus valores mínimos.

o Continúe con este proceso hasta probar todos los niveles del lazo anidado.

5. CONCLUSIONES

o La prueba de software tiene el objetivo de encontrar defectos, por lo que deben ser realizadas por una persona, o un equipo de personas, independiente del desarrollador del software.

o Realizar todas las pruebas posibles generalmente es imposible, por limitaciones de tiempo y de recursos materiales. La prueba de software consistirá en diseñar y ejecutar un número limitado de casos de prueba que permita encontrar el máximo número de defectos.

o La prueba de software usualmente requiere utilizar una combinación de técnicas de caja negra y de caja transparente para lograr un conjunto de casos de prueba consistente, combinación que dependerá de las características del software y de las limitaciones del entorno

6. REFERENCIAS BIBLIOGRÁFICAS

• Beizer, Boris; Software Testing Techniques - Second Edition; The Coriolis Group; 1990

• Black, Rex; Pragmatic Software Testing; John Wiley & Sons; 2007

• Burnstein, Ilene; Practical software testing; Springer-Verlag New York Inc.; 2003

• Harinath P. V. y otros; Software Testing Guide Book; Software Testing Research Lab; 2004

• Myers, Glenford J.; The Art of Software Testing-Second Edition; John Wiley & Sons, Inc.; 2004

• Rojas, Johanna y Barrios, Emilio; Investigación sorbe el estado del arte en diseño y aplicación de pruebas de software; Universidad Francisco José de Caldas - Bogotá; 2007