Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Apuntesdoctorado PDF
Apuntesdoctorado PDF
Informacin
Universidad de Castilla-La Mancha
Departamento de Tecnologas y Sistemas de
Informacin
Programa Oficial de Postgrado en Tecnologas Informticas
Avanzadas
ndice
Captulo 1. La importancia de las pruebas en el ciclo de vida ......................... 7
1. El proceso de pruebas en el ciclo de vida ................................................. 7
2. Las pruebas en algunas modelos..............................................................9
3. El MTPF (Minimal Test Practice Framework) .......................................9
4. El plan de pruebas .................................................................................. 12
5. Automatizacin de las pruebas .............................................................. 13
Captulo 2. Niveles de prueba ........................................................................ 19
1. Pruebas de caja negra ............................................................................. 19
2. Pruebas estructurales o de caja blanca ................................................. 20
3. Pruebas unitarias.................................................................................... 21
3.1.
1.2.
1.3.
Cobertura de condiciones...........................................................28
1.4.
Cobertura
de
condiciones/decisiones
(Decision/Condition
1.6.
1.7.
1.8.
1.9.
1.10.
1.11.
1.12.
1.13.
1.14.
1.15.
2. La mutacin ............................................................................................32
3
2.1.
2.2.
2.3.
2.4.
3. Ejercicios................................................................................................. 37
Captulo 4. Los valores interesantes ...........................................................39
1. Un estudio inicial del problema del tringulo........................................39
2. Concepto de valor interesante................................................................42
2.1.
Clases de equivalencia................................................................42
2.2.
Valores lmite..............................................................................43
2.3.
3.2.
3.3.
t-wise .......................................................................................... 47
3.4.
N-wise......................................................................................... 47
4.2.
4.3.
4.4.
4.5.
5. Ejercicios.................................................................................................52
Captulo 5. Estrategias de combinacin para la generacin de casos de
prueba...................................................................................................................53
1. Estrategias de generacin de casos de prueba .......................................53
2. Estrategias no deterministas..................................................................54
2.1.
2.2.
3.2.
3.3.
3.4.
All combinations.........................................................................59
4
3.5.
Anti-random ...............................................................................59
4.2.
5. Ejercicios.................................................................................................63
Captulo 6. Pruebas de caja negra..................................................................65
1. Pruebas de componentes ........................................................................65
1.1.
1.2.
WSDL..........................................................................................69
2.2.
2.3.
3.2.
3.3.
4.2.
4.3.
4.4.
1. Introduccin............................................................................................ 97
2. Porcentaje de deteccin de defectos.......................................................98
3. Porcentaje de defectos corregidos..........................................................98
4. Medida del retorno de la inversin (ROI)..............................................98
Captulo 9. Referencias ................................................................................ 101
Procesos principales, grupo en el que incluye los procesos de Adquisicin, Suministro, Desarrollo, Operacin y Mantenimiento.
Procesos de soporte o auxiliares, en donde estn los procesos de Documentacin, Gestin de la Configuracin, Auditora, Resolucin de
Problemas, Revisin Conjunta, Aseguramiento de la Calidad, Verificacin, Validacin,
No define, como vemos, un proceso de Pruebas como tal, sino que aconseja,
durante la ejecucin de los procesos principales o de la organizacin, utilizar los
procesos de soporte. Entre stos se encuentran los procesos de Validacin y de
Verificacin:
El proceso de Validacin tiene como objetivo determinar si los requisitos y el sistema final cumplen los objetivos para los que se construy el
producto, respondiendo as a la pregunta el producto es correcto?
Pruebas de
aceptacin
Requisitos
Pruebas de
sistema
Diseo de
alto nivel
Pruebas de
integracin
Diseo de
bajo nivel
Pruebas
unitarias
Cdigo
Figura 1. Modelo en V
A cada categora le corresponden un conjunto de prcticas de trabajo relacionadas con las pruebas, que deben realizarse segn la fase en la que se encuentre la organizacin. Las fases se describen en funcin de la cantidad de personal de desarrollo que trabaja en la organizacin. Para equipos de desarrollo
superiores a 30 personas, los propios autores recomiendan el uso de otros frameworks.
La Tabla 1 describe brevemente las actividades de cada fase y categora.
10
Fase 3
(~30 personas)
Fase 2
(~20 personas)
Fase 1
(~10 personas)
Fases
Categoras
Mantenimiento del
sistema
Mantener el sistema para
que se adapte a la evolucin de la compaa
Definicin de equipos
Creacin de un equipo de
pruebas independiente del
de desarrollo.
Los miembros de este
equipo pueden especializarse (usabilidad, seguridad, etc.).
Definicin de roles
Asignar los roles de responsable de pruebas y de
ingenieros de pruebas
(testers).
Las responsabilidades de
los testers son: gestin de
walkthroughs, gestin de,
desarrollo de casos de
prueba; gestin del sistema
de recogida de problemas;
gestin de experiencia.
Definir responsabilidades
Las responsabilidades son:
desarrollo de planes de
pruebas para cada proyecto; gestin del entorno de
pruebas; gestin del sistema de recogida de problemas; actualizacin de checklists; evaluacin de prcticas; control de necesidades
para la siguiente fase
Inspecciones
Sustitucin progresiva los
walkthroughs por inspecciones que, al requerir
preparacin previa, resultan ms eficientes.
Se definirn los roles de
cada inspector.
Walkthroughs
Realizacin de walkthroughs antes de que el
software est preparado
para su ejecucin, idealmente en la fase de diseo.
El equipo de walkthroughs
se compone de desarrolladores y diseadores, al que
puede asistir un tester.
Uso de checklists
Creacin de checklists, o
revisin de las que pudieran estar siendo utilizadas.
Verificacin y validacin
11
Gestin de riesgos
Se crear y mantendr una
base de datos de problemas
y experiencias que ayude a
predecir las reas de mayor
riesgo de los proyectos
antes de que acontezcan.
Casos de prueba
Se construyen casos de
prueba para comprobar
que se prueban las situaciones y acciones ms comunes. A la creacin de
casos de prueba se le asignarn varios testers, ya que
es una de las actividades
que requiere ms tiempo.
Se crearn varios casos
para cada escenario.
Gestin bsica
El entorno de pruebas debe
estar disponible siempre
que se requiera. Las actividades bsicas son: organizar el entorno de pruebas
para cada proyecto, mantenerlo actualizado y documentar su forma de uso.
Plan de pruebas
El plan de pruebas permite
recoger en un solo documento
todo lo relacionado con las
pruebas de cada proyecto
(p.ej., el IEEE Std. for Soft.
Test Documentation).
Es importante indicar los
diferentes hitos en el plan de
pruebas.
Planificacin
n=1
Preparar
prcticas de la
fase n
Revisar
prcticas de la
fase n
Introducir
prcticas de la
fase n
Ejecutar
prcticas de la
fase n
[no]
[s]
Cambiar?
n++
Evaluar
prcticas de la
fase n
4. El plan de pruebas
El plan de pruebas es un documento que se utiliza para indicar los recursos,
los elementos que se van a probar, las actividades, el personal y los riesgos asociados. El estndar IEEE 829 es el estndar para documentacin de las pruebas,
e indica la siguiente estructura para el plan de pruebas:
1) Identificador del documento.
2) Introduccin, resumen de los elementos y las caractersticas que se van a
probar.
3) Elementos que se van a probar (programas, mdulos)
4) Caractersticas que se van a probar.
5) Caractersticas que no se van a probar.
6) Enfoque general de la prueba.
7) Criterios de paso o fallo.
8) Criterios de suspensin y de reanudacin.
9) Documentacin asociada.
10) Actividades de preparacin y ejecucin de pruebas.
11) Entorno necesario.
12) Responsables.
12
2)
Tareas mecnicas, como la ejecucin y la monitorizacin, o las posibilidades de captura y reejecucin de casos.
3)
Tareas de generacin de casos de prueba. Respecto estas tareas, [6] indican tres enfoques:
a. Generar casos de prueba a partir de cdigo fuente para alcanzar
un nivel determinado de cobertura.
b. Dado el conocimiento del ingeniero de pruebas sobre el programa
y sobre su comportamiento esperado, generar automticamente
entradas y comprobar las salidas.
c. Dada una especificacin formal, generar automticamente casos
de prueba para una implementacin de esa especificacin.
13
casos de prueba) que ejercitan las diversas funcionalidades ofrecidas por K. As,
cada caso de prueba suele consistir en la construccin de una instancia de la
CUT, en la ejecucin de una serie de servicios sobre sta y en la comprobacin
del resultado (a lo que se le llama orculo). La Tabla 2 muestra la clase Java TestAccount, que prueba la clase de dominio Account (que representa una cuenta
bancaria) mediante tres casos de prueba, correspondientes los tres mtodos
test1, test2 y test3.
test2 crea una instancia de la CUT, ingresa 300 euros y retira 1000.
Puesto que la cuenta no tiene saldo suficiente, se espera que la CUT
lance una excepcin de saldo insuficiente (que se captura en el bloque
catch), superndose en este supuesto el caso de prueba. Si la excepcin
no se lanza, el control del programa no salta al catch y se ejecutara la
instruccin fail, que indica al entorno de pruebas que el caso no ha sido
superado.
test3 crea una instancia de la CUT, ingresa 1000 euros y luego comprueba que el saldo es de 1000 euros; despus retira 300 y comprueba
que el saldo es de 700 euros. Si se produce alguna excepcin, se salta al
bloque catch, que ejecuta el fail, indicando al entorno de pruebas que el
caso de prueba ha fallado.
Una importante ventaja de los entornos X-Unit es que los casos de prueba se
guardan en ficheros separados, lo que permite reejecutarlos segn la CUT va
siendo modificada (lo que los convierte en casos vlidos para pruebas de regresin). Una desventaja es que se requiere un esfuerzo importante para escribir
buenos casos de prueba que consigan probar todo el funcionamiento de la CUT.
Por otro lado, estos entornos no generan normalmente demasiados resultados
cuantitativos sobre los resultados de las pruebas, informando la mayora de
ellos de si los casos han encontrado o no defectos en la CUT.
14
package samples.results;
import junit.framework.*;
import samples.Account;
import samples.InsufficientBalanceException;
public class TestAccount extends TestCase {
public void test1() {
Account o=new Account();
o.deposit(1000);
assertTrue(o.getBalance()==1000);
}
public void test2() {
try {
Account o=new Account();
o.deposit(300);
o.withdraw(1000);
fail("InsufficientBalanceException expected");
}
catch (InsufficientBalanceException e) {
}
}
public void test3() {
try {
Account o=new Account();
o.deposit(1000);
assertTrue(o.getBalance()==1000);
o.withdraw(300);
assertTrue(o.getBalance()==700);
}
catch (Exception e) {
fail("Unexpected exception");
}
}
public static void main (String [] args) {
junit.swingui.TestRunner.run(TestAccount.class);
}
}
Tabla 2. Tres casos de prueba de JUnit para una clase Account (Cuenta
bancaria)
5%
100%
100%
80%
10%
15
As pues, queda bastante por hacer en cuanto a automatizacin de las pruebas. En muchas ocasiones, lo que falta es una cultura de pruebas en las propias
empresas. Rice enumera y explica los diez principales obstculos que existen en
las empresas respecto de la automatizacin del proceso de pruebas:
Falta de herramientas, debida fundamentalmente a su elevado precio o a que las existentes no se ajusten al propsito o entorno para el
que se necesitan. La primera razn parece deberse a la no mucha importancia que habitualmente se le da a la fase de pruebas, y eso que el
costo de corregir un error puede, en muchos casos, superar al de la licencia de uso. Sera conveniente evaluar el coste de correccin de defectos del software entregado y compararlo con el de la licencia de la
herramienta de pruebas.
Falta de proceso de gestin de la configuracin. Igual que las diferentes versiones del cdigo fuente, las pruebas, especialmente las de
regresin, deben someterse a un control de versiones. Recurdese que
el proceso de Gestin de la Configuracin es uno de los procesos de soporte del estndar ISO/IEC 12207 , que debera utilizarse en la ejecucin de los procesos principales, y muy especialmente en los de Desarrollo y Mantenimiento.
La herramienta no cubre todos los tipos de prueba que se desean (correccin, fiabilidad, seguridad, rendimiento, etc.). Obviamente, a la hora de elegir la herramienta, deberan tenerse priorizados los
tipos de pruebas, y entonces hacer la eleccin de la herramienta basados en esto. A veces tambin es necesario utilizar no una, sino varias
16
herramientas de prueba, as como tener en cuenta que es imposible automatizar el 100% de las pruebas.
Falta de soporte o comprensin por parte de los gestores, debido otra vez a la escasa importancia que habitualmente se le da a la fase de pruebas.
17
19
tringulo (setI, setJ, setK) y luego se comprueba nicamente si el resultado devuelto por getTipo es el correcto.
As, dependiendo de las ramas o caminos o nodos visitados por los casos de
prueba, el ingeniero estar ms o menos seguro de la buena, muy buena o mediana calidad del software objeto de estudio. Existen formas muy variadas de
medir esa cantidad de cdigo recorrido mediante lo que se llaman criterios de
cobertura.
Para Cornett [8], el anlisis de cobertura del cdigo es el proceso de:
-
Encontrar fragmentos del programa que no son ejecutados por los casos de prueba.
3. Pruebas unitarias
Las pruebas unitarias centran su aplicacin en lo que se denomina la unidad de prueba que, dependiendo del contexto, puede ser una clase, un mtodo
o un subsistema. El estndar ANSI/IEEE 1008/1987, define la unidad de prueba de la siguiente forma [9]:
Un conjunto de uno o ms mdulos de un programa, junto a con los datos de
control asociados (por ejemplo, tablas), procedimientos de uso y procedimientos de operacin que satisfagan las siguientes condiciones:
(1) Todos los mdulos pertenecen a un nico programa
(2) Al menos uno de los mdulos nuevos o cambiados del conjunto no ha pasado las pruebas unitarias (puesto que una unidad de prueba puede contener uno o ms mdulos previamente probados)
21
Las pruebas de caja negra y de caja blanca no son excluyentes, sino que son
complementarias: con las de pruebas de caja negra se buscan errores en la CUT,
y con las de caja blanca nos aseguramos de que todo el cdigo (segn el criterio
de cobertura que se haya seleccionado) ha sido recorrido.
As, un proceso de pruebas unitarias que combine tcnicas de caja negra con
tcnicas de caja blanca seguir los siguientes pasos:
1) Sea C la CUT
2) Escribir un conjunto de casos de prueba TC para probar C
3) Ejecutar TC sobre C con una herramienta de caja negra
4) Si TC descubre errores en C, entonces corregir C y volver al paso 3
5) Ejecutar TC sobre C con una herramienta de caja blanca
6) Si TC no alcanza un umbral de cobertura mnimo sobre C, entonces es
necesario escribir nuevos casos de prueba que se aaden a TC, y se vuelve al paso 3
7) Se est en este paso cuando TC no ha encontrado errores en C y cuando
TC ha recorrido todo el cdigo de C. En esta situacin, todo el cdigo ha
sido probado sin descubrir errores, con lo que la clase C tiene una calidad muy alta.
Este proceso se muestra grficamente en la Figura 5: obsrvese que, despus
de ejecutar las pruebas de caja blanca, el ingeniero de pruebas se pregunta si la
cobertura obtenida alcanza un determinado umbral, que deber haber sido
A la clase que se est probando se la llama en ingls class under test, y en muchos artculos
22
determinado con anterioridad al comienzo del proceso. Dependiendo del criterio de cobertura elegido, el umbral puede ser ms o menos exigente: as, matar
ms del 90% de los mutantes puede ser muy difcil para algunos problemas, por
lo que este valor sera un buen umbral al utilizar tcnicas de mutacin; para cobertura de sentencias, sin embargo, es necesario recorrer el 100% de ellas.
Seleccionar C (CUT)
Generar un conjunto de
casos TC para probar C
Caja negra:
buscar errores en C
usando TC
Aadir casos a TC
[se alcanza umbral]
4. Pruebas de integracin
Las pruebas de integracin se emplean para comprobar que las unidades de
prueba, que han superado sus pruebas de unidad, funcionan correctamente
cuando se integran, de manera que lo que se tiende a ir probando es la arquitectura software. Durante la integracin, las tcnicas que ms se utilizan son las de
caja negra, aunque se pueden llevar a cabo algunas pruebas de caja blanca para
asegurar que se cubren los principales flujos de comunicacin entre las unidades [10].
23
En el contexto de la orientacin a objetos, las pruebas de integracin pretenden asegurar que los mensajes que fluyen desde los objetos de una clase o
componente se envan y reciben en el orden adecuado en el objeto receptor, as
como que producen en ste los cambios de estado que se esperaban [11].
5. Pruebas de sistema
Las pruebas de sistema tienen por objetivo comprobar que el sistema, que
ha superado las pruebas de integracin, se comporta correctamente con su entorno (otras mquinas, otro hardware, redes, fuentes reales de informacin,
etc.).
Bajo este nivel de pruebas encontramos varios subniveles [10]:
1) Pruebas de recuperacin. Consisten en forzar el fallo del software y comprobar que la recuperacin se lleva a cabo de manera correcta, devolviendo al
sistema a un estado coherente.
2) Pruebas de seguridad. Intentan verificar que los mecanismos de proteccin incorporados al sistema lo protegern, de hecho, de penetraciones inadecuadas.
3) Pruebas de resistencia. Estas pruebas estn diseadas para que el sistema
requiera recursos en cantidad, frecuencia o volumen anormales. La idea es intentar que el sistema se venga abajo por la excesiva tensin a la que se lo somete.
4) Pruebas de rendimiento. En sistemas de tiempo real o sistemas empotrados, es inaceptable que el software proporcione las funciones requeridas fuera
de las condiciones de rendimiento exigidas.
6. Ejercicios
1) Escriba una clase para calcular el valor medio de 3 nmeros que se pasan
como parmetros. A continuacin, someta el programa al proceso de pruebas
descrito en la Figura 5 hasta que:
(a) Se hayan recorrido todas las sentencias.
(b) Se hayan recorrido todas las condiciones a true y a false.
La interfaz de la clase debe ser la siguiente:
24
Medio
+Medio(int a, int b, int c)
+getMedio():int
25
1. Medidas de la cobertura
La cobertura es la cantidad de cdigo recorrido por un conjunto de casos de
prueba. Existen multitud de formas de medir cunto cdigo se ha recorrido. A
continuacin se presentan algunos de ellos.
1.1.
Cobertura de sentencias
Este criterio se satisface cuando se recorren todas las sentencias del pro-
27
public
if
if
if
int getTipo() {
(i==j) { tipo=tipo+1; }
(i==k) { tipo=tipo+2; }
(j==k) { tipo=tipo+3; }
1.3.
Cobertura de condiciones
Este criterio requiere que cada decisin de cada condicin se evale a true y
a false al menos una vez.
Volviendo al ejemplo de la lnea 11 del fragmento de cdigo de la Figura 6,
los casos de prueba habrn cumplido el criterio de condiciones cuando i+j<=k
haya sido verdadero y falso, j+k<=i haya sido tambin verdadero y falso, e
i+k<=j haya sido tambin verdadero y falso, para lo cual se necesitara un mnimo de seis casos de prueba.
28
1.4.
Adems de requerir el criterio anterior, se requiere que cada condicin afecte independientemente a la decisin.
1.6.
Este criterio requiere que todas las condiciones tomen valor true y false, de
manera que se recorra la tabla de verdad completa de la decisin.
1.7.
Cobertura de caminos
Este criterio requiere que se recorran todos los caminos linealmente independientes que se encuentren en el grafo de flujo de la unidad que se est probando. El nmero de caminos linealmente independientes coincide con la complejidad ciclomtica de McCabe, la cual puede calcularse contando el nmero de
instrucciones que crean ramas. En el cdigo del Figura 6, hay 11 instrucciones if,
con lo que la complejidad ciclomtica de ese fragmento de cdigo es 11. Este valor coincide con el nmero de regiones que pueden encontrarse en el diagrama
de flujo correspondiente al cdigo que se est probando: la Figura 7 muestra el
diagrama de flujo correspondiente a dicho fragmento de cdigo, en el que pueden apreciarse once reas (incluyendo la exterior).
Para alcanzar este criterio de cobertura en este ejemplo, deberan utilizarse
once casos de prueba adecuados que recorrieran todos los posibles caminos.
29
1.9.
Cobertura de funciones
30
31
2. La mutacin
En el contexto de las pruebas del software, un mutante es una copia del programa que se est probando (programa original) al que se le ha introducido un
nico y pequeo cambio sintctico que no impide que el programa compile (por
ejemplo, cambiar un signo + por un * en una expresin aritmtica). As, puede
entenderse que el mutante es una versin defectuosa del programa original: es
decir, el mutante es el programa original, pero en el que se ha introducido o en
el que se ha sembrado un fallo.
El lado izquierdo de la Figura 8 muestra el cdigo del programa que vamos a
probar (Original) y el de algunos mutantes. En el lado derecho aparecen cuatro casos de prueba y los resultados de cada uno sobre las diferentes versiones
del programa. Obsrvese que:
32
Cdigo
Versiones
Versin
(1, 1)
(0, 0)
(-1, 0)
(-1, -1)
Original
-1
-2
Mutante 1
-1
Mutante 2
Mutante 3
Error
Error
Mutante 4
-1
-2
2.1.
Algo de terminologa
33
34
Progama
original P
Crear
mutantes M
Crear casos
de prueba T
Ejecutar T sobre
P
Ejecutar T sobre
cada mutante
vivo
Definir umbral
No
Corregir P
Se alcanz
el umbral?
Eliminar los
casos de prueba
ineficientes
S
No
P(T) es
correcta?
S
Fin
La condicin de suficiencia puede ser difcil de conseguir en muchas ocasiones, lo que puede dificultar la obtencin de casos de prueba a un coste razona-
35
Operadores de mutacin
Descripcin
Sustituir una variable por el valor absoluto de dicha variable
Sustituir una referencia variable a un array por una constante
Sustitucin de un operador aritmtico
Sustitucin del valor de una constante
Sustitucin de un operador relacional
Sustitucin de la instruccin Return
Eliminacin de una sentencia
Insercin de operador unario (p.ej.: en lugar de x, poner x)
El nmero de mutantes que puede generarse a partir de un programa sencillo, de pocas lneas de cdigo, es muy grande (pinsese que el operador AOR,
por ejemplo, puede aplicarse a cada aparicin de un operador aritmtico en el
programa original), resultando tambin muy costosas tanto la ejecucin de los
casos de prueba con cada mutante como la comprobacin de la salida del programa. Por ello, se han realizado algunos estudios encaminados a disminuir los
costes de este tipo de pruebas, evidencindose que, aplicando pocos operadores,
se pueden conseguirse los mismos resultados que si se aplicaran muchos. Los
operadores ms efectivos son el ABS, 0 (sustitucin de una variable por el valor
0), <0 (sustitucin de una variable por un valor menor que 0), >0 (sustitucin
de una variable por un valor mayor que 0), AOR, ROR y UOI.
Adems, tambin se han propuesto operadores especficos para programas
escritos en lenguajes orientados a objeto, algunos de los cuales se muestran en
la Tabla 5 .
36
Operador
Descripcin
Aadir en la subclase una variable con el mismo nombre que una variable de su superclase
Reemplazar una llamada a un mtodo por una llamada a otra versin
del mismo mtodo
Eliminar en la subclase la redefinicin de un mtodo definido en una
superclase
Cambiar el orden de los parmetros en la declaracin de un mtodo
(p.ej.: poner Persona(String apellidos, String nombre) en vez de Persona(String nombre, String apellidos)
Aadir o eliminar el modificador static
3. Ejercicios
1) Escriba casos de prueba para lograr cobertura de sentencias, de condiciones y de caminos para el problema del tringulo.
2) Escriba casos de prueba para matar a todos los mutantes del ejercicio 1
del captulo anterior.
3) Se dice que un criterio de cobertura C1 subsume a otro C2 si, para todo
programa P, cualquier caso de prueba T que satisface C1 satisface tambin C2.
Proponga algunos operadores de mutacin para conseguir que la mutacin
subsuma al criterio de decisiones. Se puede conseguir lo mismo para el criterio
de condiciones?
4) Para diagramas de flujo pueden definirse criterios de cobertura como Todos los caminos, Todos los arcos o Todos los nodos. Existen relaciones de subsuncin entre estos criterios?
37
La Figura 11 muestra ocho casos de prueba en formato JUnit para este problema. Como se observa, se han escrito dos casos para cada una de las posibles
39
) en getTipo
Puesto que no alcanzamos el umbral del 100% con este criterio de cobertura,
de acuerdo con la discusin de Cornett que mencionbamos en la pgina 21,
debemos escribir nuevos casos de prueba que ejecuten las lneas no recorridas,
que son las que se sealan con la marca
un caso que corresponda a un tringulo issceles tal que la longitud del tercer
lado sea menor que la suma de los otros dos (i+j>k), y otro que corresponda al
no tringulo que se determina en las ltimas lneas.
40
La adicin de un nuevo caso con los valores (3, 3, 1) recorre las primeras lneas indicadas, y el caso (5, 5, 10) recorre las ltimas. Por tanto, con esta pequea batera de casos conseguiramos una cobertura de sentencias del 100%.
Con este mismo conjunto de casos de prueba, tambin conseguimos cobertura
del 100% en el criterio todos los usos (descrito en la pgina 29).
Sin embargo, si utilizamos la mutacin como criterio de cobertura, estos casos de prueba matan tan slo el 2% de los mutantes que MuJava genera. MuJava es una herramienta para realizar pruebas de caja blanca de programas Java
utilizando mutacin [15]. Para el problema del tringulo, MuJava genera 479
mutantes tradicionales (correspondientes a aplicar los operadores mostrados
en la Tabla 4, pgina 36) y 82 mutantes de clase (correspondientes a los operadores que explotan especficamente las caractersticas de los lenguajes de programacin orientados a objeto, mostrados en la Tabla 5, pgina 37).
La Figura 13 muestra, en un pantallazo de MuJava, el cdigo de la clase
Tringulo y de unos de sus mutantes tradicionales: obsrvese que la instruccin
modificada (se ha sustituido el operador <= por < en la lnea 59) supone, en el
mutante la simulacin de un error introducido involuntariamente por el programador. Puesto que el objetivo de los casos de prueba es encontrar errores en
el cdigo, si seguimos el criterio de la mutacin deberamos escribir al menos un
caso de prueba que encuentre el error introducido en la zona inferior de la
Figura 13.
41
Clases de equivalencia
42
2.2.
Valores lmite
Fundamento matemtico
{d ( n / 2) 1, d n / 2 }, si n es par y k n / 2
lmites ( D, k ) =
{d k 1, d n k }, si n es impar y k < (n + 1) / 2
{d ( n 1) / 2 }, si n es impar y k ( n + 1) / 2
lmites ( D, k )* =
Ulmites(D, i)
i =1
Ecuacin 2
Ecuacin 1
Para un conjunto de dominios con esas caractersticas, se definen las siguientes dos funciones:
k
lmites ( D0 ,..., Dm 1, k )* =
Ulmites(D ,..., D
0
m 1, k )
i =1
Ecuacin 3
Ecuacin 4
lmites(D, 1)
lmites(D, 2)
lmites(D, 3)
{0, 4}
{1, 3}
{2}
{0, 3}
{1,2}
{1,2}
lmites(D,1)*
{0,4}
lmites(D,2)*
{0, 4, 1, 3}
lmites(D,3)*
{0,4, 1, 3, 2}
{0,3}
{0, 3, 1, 2}
{0, 3, 1, 2}
43
lmites(X, Y, 1)
lmites(X, Y, 2)
lmites(X, Y, 3)
lmites(X, Y, 2)*
lmites(X, Y, 3)*
Los pares de valores que tenemos en la tercera columna de la Tabla 8 representan casos de prueba: cada elemento del par representa un valor de cada uno
de los dominios.
En el mismo artculo, los autores definen tambin el concepto de permetro,
que es muy similar al de los lmites descrito, slo que, adems de los valores lmite, tambin se aaden a los casos de prueba valores pertenecientes al interior
de cada dominio.
44
pair-wise (o 2-wise)
Este criterio requiere que cada posible par de valores interesantes de cualesquiera dos parmetros sea incluido en algn caso de prueba. Se trata de un criterio ampliamente utilizado. La siguiente figura muestra un algoritmo sencillo
que genera casos de prueba con cobertura pair-wise.
45
testSuite =
PairTable[] pairTables=buildPairTables(a, b, c)
while p pairTables / p.numberOfVisits=0
i=0
found = false
while not found
if combination[i] visits p
testSuite= testSuite {combination[i]}
visit
pairs
of
combination[i]
on
pairTables
found = true
end if
i=i+1
end while
end while
Supongamos que, para el problema del Tringulo, utilizamos los valores {0,
1, 2, 3} para asignar la longitud de sus tres lados. Tendramos las tres siguientes
tablas de pares:
i/j
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(1, 0)
(1, 1)
(1, 2)
(1, 3)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(3, 0)
(3, 1)
(3, 2)
(3, 3)
i/k
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(1, 0)
(1, 1)
(1, 2)
(1, 3)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(3, 0)
(3, 1)
(3, 2)
(3, 3)
j/k
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(1, 0)
(1, 1)
(1, 2)
(1, 3)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(3, 0)
(3, 1)
(3, 2)
(3, 3)
46
3.3.
t-wise
N-wise
Figura 16. Dos de los casos de prueba del Tringulo, que son
redundantes
47
48
cin de los mutantes matados por tc1 y tc2 no es vaca, el algoritmo devuelve un
conjunto formado tc1 y tc2.
Cuando se encuentran casos de prueba que matan n mutantes, se agregan a
la variable requiredTC (lnea 9) y se eliminan los mutantes muertos (lneas 1013). De este modo, el algoritmo no vuelve a considerar los mutantes que han
sido muertos en iteraciones anteriores.
1. reduceTestSuite(completeTC : SetOfTestCases, cut : CUT, mutants : SetOfMutants) :
SetOfTestCases
2. testCaseResults = execute(completeTC, cut, mutants)
3. requiredTC =
4. n=|mutants|
5. while (n>0)
6. mutantsNowKilled =
7. testCasesThatKillN = getTestCasesThatKillN(completeTC, n, mutants, mutantsNowKilled,
testCaseResults)
8. if |testCasesThatKillN>0| then
9. requiredTC = requiredTC testCasesThatKillN
10. for i=1 to |testCasesThatKillN|
11.
testCase = testCasesThatKillN[i]
12.
testCase.removeAllTheMutantsItKills()
13. next
14. n = |mutants|-|mutantsNowKilled|
15. else
16. n = n 1
17. end if
18. end_while
19. return requiredTC
20.end
49
Ejemplo
50
4.2.
Algoritmo HGS
Mejoras de Gupta
Con Jeffrey [19], Gupta le agrega redundancia selectiva. La redundancia selectiva permite seleccionar los casos de prueba que, para
cualquier requisito dado, proporciona la misma cobertura que otro
caso previamente seleccionado. As, quiz T' alcance el criterio de
condiciones, pero quiz no el de todos los mutantes; por tanto, un
nuevo caso t puede ser aadido a T' si aumenta la cobertura en cuanto a mutantes: ahora, T' no aumentar el criterio de condiciones, pero
s el de mutantes.
Con Tallam [20], la seleccin de los casos de la prueba se basa en tcnicas de Anlisis de Conceptos. Segn los autores, este algoritmo obtiene un conjunto reducido con el mismo tamao y en un tiempo similares al algoritmo HGS original.
51
4.4.
McMaster y Memon [22] presentan tambin un algoritmo voraz. El parmetro considerado para incluir los casos de prueba en el conjunto reducido se basa
en las pilas de llamadas nicas que los casos de prueba producen en el programa bajo prueba.
5. Ejercicios
1) Suponga que disponemos de un sistema como el mostrado en la figura.
Proponga valores interesantes de tipo Persona para las operaciones add y setJefe del tipo Proyecto.
{incluido}
Proyecto
*
miembros
+add(p:Persona)
+setJefe(p:Persona)
jefe
Persona
categora
<<enum>>
Categora
nombre:String
apellidos:String
fechaNac:Date
52
53
2. Estrategias no deterministas
En este tipo de estrategias, el azar cumple siempre un papel importante en
la determinacin de qu casos de prueba se generarn. As, no se asegura que
dos ejecuciones del mismo algoritmo produzcan siempre los mismos resultados.
2.1.
El siguiente algoritmo genera casos de prueba para lograr cobertura pairwise, donde el valor de k se fija arbitrariamente. Cuanto mayor es k, menor es el
tamao del conjunto de casos, si bien a partir de k=50, el tamao del conjunto
permanece estable.
Se parte de un conjunto T de casos de prueba
Sea UC el conjunto de pares de valores de dos parmetros cualesquiera todava no cubiertos
por los casos preseleccionados
while UC
UC={pares de valores no cubiertos por T}
selectedTestCase=
for i=1 to k
Seleccionar la variable y el valor incluido en ms pares de UC
Ordenar aleatoriamente el resto de variables
Para cada variable determinada en el paso 5, seleccionar el valor incluido en ms pares de UC
y crear as un caso de prueba, tc
if tc visita ms pares que selectedTestCase then
selectedTestCase=tc
endIf
endFor
marcar en UC los pares cubiertos por selectedTestCase
T=T {selectedTestCase}
endWhile
2.2.
Algoritmos Genticos
De forma general, los algoritmos genticos constituyen un mtodo de resolucin de problemas de minimizacin. Parten de una solucin inicial, que se va
aproximando a la ptima segn una serie de iteraciones. De la solucin inicial
van construyndose soluciones mejores de acuerdo con una funcin objetivo
(fitness).
54
2.2.1
Pargas et al. utilizan el algoritmo mostrado en la Figura 22 para lograr criterios de cobertura altos.
En la primera lnea se calcula CDGPaths, que representa el grafo de dependencias de control del programa que se va a probar. Un grafo de dependencia de
control es un grafo dirigido acclico cuyos nodos representan sentencias y cuyos
arcos representan dependencias de control entre sentencias. Un nodo Y depende por control de otro X si y slo si: (1) cualquier nodo intermedio en el camino
de X a Y est postdominado por Y; y (2) X no est postdominado por Y. Se dice
adems que un nodo X est postdominado por otro Y si para llegar desde X a la
salida es preciso pasar siempre por Y.
A continuacin se inicializa Scoreboard, que guarda el registro de los requisitos de prueba (TestReq) satisfechos. Scoreboard puede ser un vector de bits si
se desea lograr cobertura de sentencias, un vector de enteros si deseamos conocer la frecuencia de ejecucin de cada sentencia o, en general, una estructura de
datos adecuada al criterio de obertura considerado.
El siguiente paso es la generacin de la poblacin inicial (conjunto inicial de
los valores de entrada). A continuacin (bucle de las lneas 4 a 14), comienza el
proceso de generacin de los casos de prueba, bastante legible sin mayor explicacin. Como excepcin, hay que resaltar que el clculo del fitness se hace en
funcin del nmero de nodos de CDGPaths alcanzados por el caso de prueba
teniendo en cuenta el requisito de prueba actual (variable r en el algoritmo).
55
1.
Crear CDGPaths
6.
7.
8.
9.
10.
generar NewPopulation
11.
12.
13.
endwhile
14. endwhile
15. final = conjunto de casos de prueba que satisfacen TestReq
16. devolver (TestReq, final)
2. Calcular fitness de P
3. while no se cumpla la condicin de parada
4.
5.
Aplicar Selection a los individuos de P para crear Pmating, con m-n individuos
6.
Cruzar Pmating
7.
Mutar Pmating
8.
P=Elite + Pmating
9.
Evaluar P
10.
11. endwhile
12. devolver el mejor caso
56
2.2.3
El algoritmo de las hormigas representa los casos de prueba en un grafo como el siguiente:
hi , j =
C i , max C i , j + 1
C i , max C i , min + 1
57
1.
2. Inicializar feromonas
3. while no se alcance la condicin de parada
4.
5.
6.
evaluar Sk
7.
depositar feromonas
8.
endfor
9.
actualizar feromonas
10.
11. endwhile
12. devolver el mejor caso
[ ] [ ]
=
[ ] [ ]
Pi , j
i, j
vi
h =1
i, j
i ,h
i,h
rmetro pi; i,j y i,j son, respectivamente, el valor de la heurstica asignada al eje
i,j y la cantidad de feromona; y son factores de peso asignados en funcin de
la importancia que quiera darse a la heurstica o a la feromona.
La actualizacin de las feromonas se realiza cuando cada hormiga ha generado un caso de prueba y se hace con la siguiente ecuacin:
i , j = i , j + i , j + i, j
Adems de estas ecuaciones, se utilizan otras para representar las tasas de
persistencia y evaporacin de las feromonas.
3. Estrategias deterministas
En estas estrategias, dos ejecuciones del mismo algoritmo producen siempre
los mismos resultados con el mismo conjunto de entradas. Se describen a continuacin algunas de esta categora.
58
3.1.
Each choice
Base choice
Partly pair-wise
All combinations
Anti-random
Esta estrategia, debida a Malaiya [24], se basa en que cada caso de prueba
debera seleccionarse de forma que tenga la mayor distancia con respecto a los
dems. Los parmetros y los valores interesantes se codifican en un vector binario.
Los casos de prueba se van seleccionando en funcin de su distancia de
Hamming o de su distancia cartesiana con respecto a los que se han generado
con anterioridad.
Supongamos que, para el problema del tringulo, tenemos los valores
{1,2,3}, {4,5} y {6,7} para los tres lados, que se codifican segn la Tabla 9. Anti-
59
random empieza con la seleccin de un caso arbitrario. Sea el (1,4,6) este primer
caso, que corresponde a la palabra 0000; si se utiliza la distancia Hamming, el
siguiente caso ser aqul que tenga el mayor nmero diferente de bits, con lo
que se selecciona la palabra 1111, correspondiente al caso (3,5,7). El siguiente
caso ser aquel cuya suma de distancias Hamming a los dos casos seleccionados
sea mayor.
Valor
A (*)
B
C
Cdigo
1
00
01
10
11
60
A continuacin se hace una revisin rpida de tres mtodos basados en algoritmos de minimizacin: uno basado en Bsqueda Tab y dos en algoritmos genticos, si bien existen otras posibilidades, como el uso de Simmulated Annealing o enfoques hbridos como el propuesto por [25].
4.1.
Bsqueda Tab
Puesto que el objetivo de estos autores es alcanzar la mayor cobertura posible, utilizan un grafo que representa el flujo de control del programa, en cuyos
nodos se anota si el propio nodo ha sido alcanzado, cuntas veces lo ha sido y
cul es el mejor caso de prueba que lo ha alcanzado. Cuando no hay ramas inalcanzables, el mximo valor posible para la cobertura es el 100%, mientras que
ser desconocido en caso de que las haya. Por este motivo establecen como cri-
61
terio de parada o haber alcanzado todas las ramas, o que el algoritmo haya superado un nmero de iteraciones prefijado. Adems, cada solucin se caracteriza por su conjunto de valores de entrada. El coste de una solucin, fundamental
para que el algoritmo funcione eficazmente, se calcula considerando que el mejor caso de prueba es aquel que tiene ms posibilidades de que sus vecinos permuten entre ramas o, lo que es lo mismo, aquel que alcanza el nodo con valores
lmite. Por ejemplo, si la condicin es x!=y, la funcin de coste ser |x-y| (vase
la referencia para conocer el resto de detalles de clculo de la funcin de coste).
Para calcular los vecinos candidatos, los autores se basan en que, si un caso
de prueba cubre al padre de un nodo pero no a su hijo, entonces puede encontrarse un vecino que alcance al hijo utilizando el caso que cubre al padre a partir
de la mejor solucin. A partir de sta generan 2n vecinos cercanos y 2n vecinos lejanos (donde n es el nmero de variables de entrada del programa). Los
candidatos se comprueban frente a la lista tab, rechazndose aquellos que ya
existen. En la siguiente iteracin se repite el proceso, con la diferencia de que el
nodo objetivo puede haber cambiado si alguno de los candidatos alcanz el entonces nodo objetivo.
4.2.
Baudry et al. [27] parten de un conjunto inicial de casos de prueba. Su algoritmo se ejecuta en varias iteraciones, en cada una de las cuales se aplican mutaciones a los casos de prueba. El algoritmo memoriza los casos de prueba que
pueden mejorar la calidad del test suite, la cual se mide mediante una funcin
de fitness.
El algoritmo dispone de cinco funciones principales:
1) Fitness del test suite, que se mide utilizando algn criterio de cobertura.
2) Fitness relativo de un caso de prueba tc: se calcula en funcin del fitness
del test suite, TS:
relFitness(TS, tc) = fitness(TS {tc}) - fitness(TS)
3) Memorizacin, que memoriza o no un caso de prueba en funcin de fitness relativo de dicho caso.
62
4) Mutacin, que genera nuevos casos de prueba a partir de otros. Los casos
de prueba origen se toman aleatoriamente del test suite, si bien la probabilidad de tomar un caso u otro depende del fitness relativo de cada caso.
5) Filtrado, que va eliminando los casos que no se utilizan con el fin de preservar la memoria.
5. Ejercicios
1) Partiendo del conjunto de casos de prueba (1, 1, 1), (2, 2, 2), (3, 3, 3) y
(4,4,4) para el problema del tringulo, construya un conjunto de ms calidad
aplicando, manualmente, un algoritmo gentico. Cmo evoluciona la calidad
del conjunto al generar cada nueva poblacin?
63
1. Pruebas de componentes
En terminologa UML, un componente es una parte fsica reemplazable de
un sistema que empaqueta su implementacin, y que es conforme a un conjunto
de interfaces a las que proporciona su realizacin [29]. Esto significa, sencillamente, que el componente ofrece una serie de servicios (mtodos) a sus usuarios
a travs de una interfaz; las operaciones incluidas en la interfaz se implementan
dentro de la lgica del componente.
Un componente, por tanto, representa una unidad de construccin reutilizable, que puede ensamblarse para formar aplicaciones.
Habitualmente, el componente se percibe como una pieza de la que se conoce la interfaz que ofrece y las salidas que aporta, por lo que pueden considerarse
paradigmticos para considerarlos cajas negras.
1.1.
pers, o adaptadores construidos durante las pruebas) para la prueba de componentes. Esencialmente, un BIT wrapper es una clase que ofrece la misma interfaz que el componente para el que se ha construido. En la fase de pruebas del
componente, se ejecutan las operaciones de ste a travs del BIT wrapper, que
posee funcionalidades como la comprobacin de las precondiciones de la operacin antes de llamar a la operacin real, y la comprobacin de las postcondiciones tras su ejecucin. Adems, el BIT wrapper puede mantenerse para que capture las llamadas que los clientes hacen a las operaciones del componente
(Figura 27).
65
La violacin de las restricciones se detectan en el momento en que ocurren, de manera que se evita su propagacin a otros componentes.
66
Tanto el BIT wrapper como el Test driver pueden generarse automticamente: para el primero es preciso disponer de una descripcin formal del componente (el autor utiliza el lenguaje Resolve, aunque podra emplearse cualquier
otro); para la generacin del segundo podran usarse generadores aleatorios, de
valores lmite, etc.
1.2.
Mutacin de interfaces
67
Interfaz
Servidor
Interfaz
mutada
Cliente
Servidor
68
2.1.
WSDL
69
- <message name="validar0Request">
<part name="numeroDeTarjeta"
type="xsd:string" />
<part name="importe" type="xsd:double" />
</message>
- <message name="validar0Response">
<part name="return" type="xsd:boolean" />
</message>
- <portType name="VisaPortType">
- <operation name="validar">
<input name="validar0Request"
message="tns:validar0Request" />
<output name="validar0Response"
message="tns:validar0Response" />
</operation>
</portType>
El cliente que utiliza el servicio web necesita una clase que acte como proxy
entre l mismo y el servicio web ofertado por el servidor. Cuando el proxy recibe
del cliente una solicitud de llamada al servicio web, el proxy la traduce a un
mensaje SOAP, que enva al servidor; ste, entonces, lo ejecuta, y devuelve un
mensaje SOAP al proxy, que traduce el mensaje a objetos Java, .NET, etc. y entrega el resultado al cliente que efectu la peticin.
La siguiente figura muestra la relacin entre el proxy, el servicio web y la
clase que lo implementa: el servicio web (en el centro) ofrece a los clientes acceso a la operacin validar(String, Double); la operacin se encuentra realmente
implementada en la clase situada abajo (Visa), y podra incluir llamadas a otros
mtodos de otras clases, acceso a una base de datos, acceso a otros servicios
web, etc. El elemento de la izquierda (VisaWSStub) es la clase que acta de
proxy entre los clientes y el servicio web. Ntese que esta clase incluye, adems
de otras, la operacin validar(String, Double). El proxy mostrado se ha obtenido de forma automtica con un entorno de desarrollo, por lo que sus miembros
pueden variar de unos casos a otros. El atributo _endpoint representa la URL en
la que se encuentra publicado el servicio web.
70
La aplicacin cliente hace entonces uso del proxy para acceder al servicio
web, por ejemplo con un trozo de cdigo como el que sigue:
protected void validarDisponibilidadDeCredito(double importe) throws Exception
{
// Se intancia el proxy
VisaWSStub stub = new VisaWSStub();
// Se le dice al proxy dnde puede encontrar el servicio web
stub.setEndpoint("http://161.67.27.108:8988/soap/servlet/soaprouter");
// Se llama al mtodo ofertado por el proxy
if (!stub.validar("", new Double(5.0)).booleanValue())
throw new Exception("Operacin no admitida");
}
Figura 33. Acceso desde el cliente al servicio web a travs del proxy
2.3.
Offutt y Xu [32] proponen la utilizacin de perturbacin de datos para realizar las pruebas de servicios web. Los mensajes SOAP se modifican y se utilizan
como casos de prueba. La tcnica de la perturbacin de datos utiliza tres mtodos para probar los servicios web:
(1) Perturbacin de los valores de los datos.
(2) Perturbacin de la comunicacin RPC.
(3) Perturbacin de la comunicacin de datos.
En perturbacin de valores, se sustituyen los valores de los datos en los
mensajes SOAP por otros valores basndose en la tcnica de valores lmite (la
Tabla 10 muestra los valores lmite de cinco de los diecinueve tipos de datos de
SOAP).
71
Tipo de dato
String
Valores lmite
Boolean
true, false
<soapenv:Body>
<adminLogin soapenv:encodingStyle=>
<arg0 xsi:type=xsd:string>turing</arg0>
<arg1 xsi:type=xsd:string>enigma</arg1>
</adminLogin>
</soapenv:Body>
<soapenv:Body>
<adminLogin soapenv:encodingStyle=>
<arg0 xsi:type=xsd:string>turing OR 1=1</arg0>
<arg1 xsi:type=xsd:string>enigma OR 1=1</arg1>
</adminLogin>
</soapenv:Body>
en el objeto receptor, as como que producen en ste los cambios de estado que
se esperaban.
Gallagher et al. describen una metodologa para realizar pruebas de integracin mediante el modelado del sistema como una mquina de estados [11]. Las
mquinas de estado se utilizan con mucha frecuencia para describir el comportamiento de clases individuales. Una mquina de estados para una clase C puede describirse mediante una tupla (V, F, P, S, T), donde:
73
tes, se parte de las transiciones que salen del componente, y se ejecuta a continuacin un proceso iterativo por el que se van aadiendo las transiciones llamadas por las transiciones que ya estn en el conjunto.
Despus se construye un grafo de flujo a partir de la mquina de estados
combinada, en el cual se consideran:
Los estados origen o destino de las transiciones que se han identificado como relevantes.
4. Ejercicios
1) Explique las similitudes entre las pruebas de componentes mediante mutacin de interfaces y las pruebas de servicios web mediante perturbacin de
datos.
2) Suponga que tenemos un sistema orientado a objetos como el de la figura
siguiente, y que queremos probar el correcto funcionamiento de este sistema
ejecutando los servicios que ofrece la clase C1. Razone si tendra utilidad inyectar fallos en las clases interiores (C2 a C5) para realizar las pruebas.
C1
C2
C3
C4
C5
74
Correccin: no debe haber ambigedad en ningn requisito. Cualquier requisito no debe tener ms que una interpretacin.
75
76
Supongamos un sistema bancario en el que hay una funcin de retirada de efectivo en la que se hace una comprobacin del saldo de la cuenta y del crdito
concedido a dicha cuenta. La funcin conoce el importe que se desea retirar, el
saldo de la cuenta y el crdito concedido (el crdito es un nmero negativo, que
representa el saldo negativo que se autoriza alcanzar a este cliente). Las posibles
acciones son las siguientes:
Autorizar la retirada del efectivo y enviar una carta.
Autorizar la retirada del efectivo.
Suspender la cuenta y enviar una carta.
La funcin tiene los siguientes requisitos:
Si saldo-importe>=0, se autoriza la retirada de efectivo.
Si saldo-importe<0 ^ saldo-importe>=crdito, se autoriza la retirada y
se enva una carta.
Si saldo-importe<0 ^ saldo-importe<crdito, se suspende la cuenta y se
enva una carta.
Del enunciado se extraen 3 efectos:
E1: autorizar la retirada de efectivo.
E2: suspender la cuenta.
E3: enviar la carta.
Estos efectos se consiguen a partir de las siguientes causas:
C1: saldo-importe>=0.
C2: saldo-importe>=crdito.
A continuacin, se construye la tabla de decisin:
C1: saldo-importe>=0
C2: saldo-importe>=crdito
E1: autorizar retirada
E2: suspender la cuenta
E3: enviar la carta
1
0
0
0
1
1
Reglas
2 3
0 1
1 0
1 0 1 -
4
1
1
1
0
0
6) Revisin de la consistencia de la tabla de decisin, lo que permitir obtener los casos de prueba que cubran el 100% de los requisitos funcionales.
7) Revisin de los casos de prueba por parte de los autores de los
requisitos, de modo que si se encuentra algn problema con algn caso de
prueba, los requisitos asociados con el caso de prueba podrn ser corregidos y
los casos de prueba rediseados.
8) Validacin de los casos de prueba con los expertos en el dominio, con objeto de encontrar posibles problemas en los requisitos de los cuales
proceden.
77
9) Revisin de los casos de prueba por parte de los desarrolladores, de modo que stos conozcan mejor los requisitos del sistema que tienen
que construir y puedan orientar la construccin hacia la superacin de estos
casos de prueba.
10) Utilizacin de casos de prueba en las revisiones del diseo.
Con esta tarea, se puede comprobar si el diseo que se est realizando satisfar
los casos de prueba y, por tanto, los requisitos. Igualmente, podra llegarse a la
conclusin de que alguno de los requisitos no sea factible.
11) Utilizacin de casos de prueba en las revisiones del cdigo.
Puesto que cada fragmento de cdigo sirve un fragmento de los requisitos, los
casos de prueba pueden utilizarse para comprobar que, efectivamente, el cdigo
se comporta como se esperaba.
12) Verificacin del cdigo contra los casos de prueba. En este ltimo paso, se construyen casos de prueba ejecutables a partir de los casos de
prueba de alto nivel. Cuando todos los casos ejecutables se ejecuten satisfactoriamente contra el cdigo, puede decirse que se ha verificado el 100% de la funcionalidad.
2. Secuencias de mtodos
En el contexto de las pruebas de sistemas orientados a objetos, Kirani y Tsai
[34] consideran la secuencia como un concepto fundamental para la prueba de
clases. Una secuencia representa el orden correcto en el que los mtodos pblicos de una clase pueden ser invocados. De acuerdo con estos autores, una de las
aplicaciones de las secuencias es la prueba de clases a partir de su especificacin
como una mquina de estados.
As, puede utilizarse la especificacin del comportamiento de una cierta clase en forma de mquina de estados para generar casos de prueba, ejecutarlos y
medir nuevos criterios de cobertura. En el ejemplo de la Figura 37, se conseguira una cobertura completa de estados con la secuencia m1.m2.m3.m4, mientras
que deberan ejecutarse otras secuencias para lograr cobertura de transiciones o
cobertura de caminos. A partir de aqu surgen con facilidad otros criterios de
cobertura, como la ejecucin de cada camino cero veces, una vez y ms de una
vez, cobertura de guardas, de acciones, etc.
78
m3
s3
m3
m1
s0
m2
s1
s2
m4
m3
m4
s4
m4
Propuesta de Tse y Xu
79
var X : AccountSort .
var M : Money .
var N : Money .
constructor Account()
ensure {balance(result) == balance(empty)} .
method credit(M : Money)
require {M > 0} .
ensure {balance(post-self) ==
balance(creditS(pre-self, M))} .
eq representa propiedades de las operaciones descritas mediante ecuaciones. Por ejemplo, eq balance(empty) = 0 indica que el resultado de
ejecutar la operacin balance (en ingls, saldo) sobre una cuenta
creada con la operacin empty (en ingls, vaca), es cero; eq debitS(empty, N) = creditS(empty, - N) indica que sacar N euros de una
80
cuenta vaca (cuyo saldo es cero) es lo mismo que sacar los mismos N
euros a crdito.
N euros de una cuenta X de la que se han sacado a crdito M euros supone el cobro de un 5% de comisin sobre el importe sacado, si ste es
menor que 200 euros y el saldo de la cuenta es negativo.
La capa de restricciones del caso de la figura incluye, por ejemplo, una invariante que indica que el saldo de la cuenta debe ser siempre superior al crdito
concedido (invariant {balance(self) >= - creditLimit}); una postcondicin sobre
el constructor Account que denota que el saldo de una cuenta recin creada es
cero (constructor Account() ensure {balance(result) == balance(empty)}), y
una precondicin para la operacin credit(M : Money) que expresa que el importe que se saca a crdito debe ser positivo (require { M>0 }).
A partir de estas consideraciones, los autores realizan una particin del espacio de estados de la clase, obteniendo estados abstractos por cada trmino
booleano de la capa funcional. A partir, por ejemplo, de la propiedad eq balance(empty)=0 podran obtenerse los estados en que la cuenta tiene saldo negativo, saldo cero y saldo positivo. Combinando adems estos estados con la invariante de la capa de objeto (invariant {balance(self) >= - creditLimit}), se podran obtener los siguientes cinco subestados:
balance(self) = -creditLimit
balance(self) = 0
balance(self) > 0
Puesto que el valor de creditLimit es 1000, los estados concretos son los
siguientes (ntese la adicin de un estado inicial adicional, en el que el objeto se
encuentra antes de ser creado; igualmente podran crearse estados finales si la
clase tuviera destructores):
S0= { no creado }; S1= { b==1000 }; S2= { -1000<b<0}; S3= { b==0}; S4={ b>0}
81
Mtodo ASTOOT
La semntica incluye una lista de axiomas que describen la relacin entre funciones, utilizndose en muchos casos axiomas de reescritura para esta descripcin. As, dos secuencias de operaciones S1 y S2 son equivalentes si se pueden usar los axiomas como reglas de reescritura para
transformar S1 en S2.
82
(2)
83
En otras palabras, cuando es imposible distinguir O1 de O2 usando las operaciones de C. Si se dispusiera de una cantidad de tiempo infinita para comprobar si dos objetos son observacionalmente equivalentes, podra utilizarse el siguiente procedimiento para comprobar la correccin de la clase C:
Sea U el conjunto de tuplas (S1, S2, etiqueta), donde S1 y S2 son secuencias de mensajes, y etiqueta es un texto que vale equivalente o no
equivalente.
Para cada tupla de U, enviar las secuencias S1 y S2 a O1 y O2 y comprobar si ambos objetos son observacionalmente equivalentes.
La equivalencia observacional de dos objetos puede resolverse con un mtodo tipo equals; sin embargo, la finitud del tiempo para realizar las pruebas
es irresoluble, por lo que sus autores la han adaptado en la familia de herramientas ASTOOT. El componente de generacin de casos de prueba toma la
descripcin sintctica y semntica de la clase que se va a probar (Figura 40) y la
traduce a una representacin arborescente. Con esta representacin, lee una
secuencia de operaciones suministrada por el usuario y le aplica una serie de
transformaciones para obtener secuencias de operaciones equivalentes. Las
operaciones incluidas en las secuencias son simblicas, en el sentido de que carecen de parmetros reales. Por ltimo, y teniendo en cuenta la asuncin explicada ms arriba, la comprobacin de la correccin de la clase la realizan pasando valores reales a los parmetros de los mensajes contenidos en las secuencias
de cada tupla.
3.3.
Henkel y Diwan [37] han desarrollado una herramienta que obtiene de manera automtica especificaciones algebraicas a partir de clases Java. Comienzan
obteniendo una lista de secuencias de operaciones vlidas mediante llamadas
sucesivas a los constructores de la clase y a algunos de sus mtodos, pasando
valores adecuados a los parmetros de estas operaciones. Si alguna de las se-
84
A partir de las ecuaciones se generan los axiomas, que constan de dos secuencias y una serie de variables cuantificadas. As, de la ecuacin de la izquierda, se obtiene el axioma de la derecha:
IntAdd(size(IntStack().state).retval,1).retval = s:IntStack, i:int
size(push(IntStack().state, 3).state).retval
IntAdd(size(s).retval,1).retval =
size(push(s, I).state).retval
Muchos de los axiomas generados son redundantes, por lo que con posterioridad se detectan y se eliminan aplicando reglas de reescritura, para lo que primero deben identificarse stas de entre el conjunto de axiomas. Se considera
que un axioma es una regla de reescritura si: (1) el lado izquierdo y el derecho
tienen diferente longitud; y (2) las variables libres que aparecen en lado ms
85
corto son un subconjunto de las variables libres que aparecen en el lado derecho.
Cobertura de transiciones
Este criterio se satisface cuando el conjunto de casos de prueba contiene casos que provocan el disparo de todas las transiciones contenidas en la mquina
de estados.
4.2.
Cobertura de predicados
Los predicados son las expresiones booleanas que etiquetan las guardas
(condiciones en las transiciones de las mquinas de estado). Formalmente, un
predicado es una expresin booleana compuesta de clusulas y cero o ms operadores booleanos. A su vez, una clusula es una expresin booleana formada
por expresiones booleanas combinadas con operadores no booleanos (por ejemplo, operadores relacionales). Por ltimo, una expresin booleana es una expresin cuyo valor puede ser true o false. Esto se ilustra en la Tabla 11.
a
b
a>b
a<b
(a>b) and (b<c)
Expresin booleana
Clusula
Predicado
86
B
0
0
1
1
0
0
1
1
C
0
1
0
1
0
1
0
1
A or B
0
0
1
1
1
1
1
1
(A or B) and C
0
0
0
1
0
1
0
1
4.3.
Este criterio se satisface cuando el conjunto de casos de prueba contiene casos de prueba que recorren, para un estado dado, todos los pares de transiciones
de entrada y salida de ese estado.
As, para la mquina de estados de la Figura 43, este criterio ser satisfecho
si el conjunto de casos de prueba contiene casos que recorran (m1, m3), (m1,
m4), (m1, m5), (m2, m3), (m2, m4) y (m2, m5).
87
m3
m1
m4
S
m2
m5
4.4.
88
Definir el conjunto de secuencias de mensajes MS a partir de los diagramas de secuencia. Cada secuencia comienza con un mensaje m sin
predecesor (habitualmente, un mensaje enviado al sistema por un actor) y el conjunto de mensajes cuya ejecucin dispara m (aquellos cuyo
inicio est en el foco de control en que termina m).
Analizar subcasos, que bsicamente consiste en construir varias secuencias a partir de las posibles instrucciones condicionales que anotan
los diagramas de secuencia.
Identificar los conjuntos de valores de prueba, que se construyen a partir de los tipos de los parmetros de los mtodos y del anlisis de los
diagramas de clases del sistema.
Seleccionar, para cada mensaje de la secuencia, las situaciones relevantes en que el mensaje puede ocurrir y, para cada valor de prueba, valores vlidos que puedan incluirse en el mensaje.
Obtener procedimientos de prueba, que puede hacerse automticamente con los datos obtenidos en los pasos anteriores.
As, a partir del diagrama de secuencia mostrado en la Figura 44, se identifican las siguientes secuencias de mensajes:
MS_1: 1.start(), 1.1.open()
MS_2: 2.enterUserName(String)
MS_3: 3.enterPassword(String)
MS_4: 4.loginUser(),
4.1.validateuserIDPassword(String, String)
4.2.setupSecurityContext(), 4.2.1.new UserID()
4.3.closeLoginSelection()
89
MS_4.1: 4.loginUser(),
4.1.validateuserIDPassword(String, String)
4.2.setupSecurityContext(), 4.2.1.new UserID()
MS_4.2: 4.loginUser(),
4.1.validateuserIDPassword(String, String)
4.3.closeLoginSelection()
90
Relacin de uso directa: la clase A usa la clase B cuando existe una asociacin desde A hacia B, o bien cuando hay una dependencia con el estereotipo
<<usa>> desde A hacia B. Este conjunto de relaciones se llama SDU (Set of Direct Usage relationship). Ntese que una asociacin no dirigida representa
realmente dos relaciones de este conjunto.
Relacin de uso transitiva: es el conjunto formado por la clausura transitiva de SDU.
Relacin de uso transitiva real: si existe una relacin transitiva entre
las clases A, B y, adems, el cdigo fuente obtenido del diagrama de clases permite la interaccin entre dos instancias de A y de B, entonces se dice que dicha
relacin transitiva es real.
Interaccin de clases (interaccin potencial): siendo A, B dos clases,
ocurre si y slo si A Ri B y B Ri A, siendo i distinto de j. [La interaccin es potencial porque tal vez no llegue fsicamente a producirse en la ejecucin del sistema].
Interaccin entre objetos (interaccin real): siendo A, B dos clases,
ocurre si y slo si (1) A Ri B y B Ri A, siendo i distinto de j, y (2) Ri y Rj son relaciones transitivas reales. [La interaccin es real porque se produce la interaccin entre ambos objetos en la ejecucin del sistema obtenido del diseo].
El criterio de prueba propuesto es el siguiente: para cada interaccin entre clases, o bien se obtiene un caso que prueba la interaccin entre objetos, o
bien se obtiene un informe mostrando que tal interaccin no es factible.
Puesto que la tarea de producir casos de prueba o informes es imposible si el
nmero de interacciones es muy alto, es preciso obtener diseos que disminuyan el nmero de interacciones, de modo que se haga factible as la prueba
completa del diseo de clases.
Antes de someterlo al criterio de pruebas, el diseo de clases debe ser evaluado para conocer el nmero de interacciones entre clases, modificndolo si es
muy alto y tal mejora es posible, o rechazndolo directamente en otro caso. La
mejora del diseo puede lograrse reduciendo el acoplamiento o anotndolo con
restricciones que eviten la codificacin de interacciones entre objetos propensas
a error. Los autores proponen la anotacin utilizando los estereotipos <<create>> (para indicar que la clase A crea instancias de la clase B),
91
<<use_consult>> (para indicar que la clase A slo utiliza mtodos tipo get de B)
y <<use_def>> (para indicar que la clase A modifica el estado de las instancias
de B). Estos estereotipos se utilizan en el proceso de construccin del Grafo de
Dependencias de Clases (en ingls Class Dependency Graph, o CDG), que representa las relaciones transitivas entre clases junto a las relaciones de herencia
e implementacin. La siguiente figura muestra algunos ejemplos sobre la obtencin del CDG, en la que aparecen algunas etiquetas aadidas a los nodos del
CDG para representar el tipo de relacin existente.
nbPaths
((complejidad ( P ) complejidad ( P ))
i
i =1
j >i
complejidad ( P) =
nbCrossed
complejidad ( IH , P)
i =1
92
complejidad ( IH , P ) =
nbDP
complejidad (dp )
i =1
Por ltimo, la complejidad de un camino de descendientes es el nmero de interacciones potenciales entre las clases que hay en ese camino. El caso peor se dara cuando todas las clases estuvieran relacionadas con todas las
clases, lo que supone un valor mximo de n(n-1). De manera general, la complejidad de un camino se corresponde con la Ecuacin 8, en donde h representa
la altura del camino:
comlejidad (dp) = h (h 1)
Ecuacin 8. Complejidad de un camino de descendientes
93
94
Para ello suelen utilizarse listas de comprobacin (checklists), que enumeran defectos y en los que el revisor anota su presencia o ausencia. En puede
consultarse una lista de comprobacin de errores tpicos del lenguaje Java, entre los que se incluyen el control de overflows y underflows, restriccin adecuada del acceso a los miembros de las clases, control de apertura y cierre de ficheros, etc.
9. Ejercicios
1) Escriba casos de prueba que cumplan los criterios de cobertura mencionados en la Seccin 4 para la siguiente mquina de estados, que representa el
comportamiento de una cuenta corriente:
2) Escriba el cdigo correspondiente a la mquina de estados del ejercicio anterior. Somtalo a los casos de prueba que ha propuesto. Analice si hay algn tipo
de relacin entre la cobertura de la mquina de estados y la del cdigo fuente.
95
1. Introduccin
Como es bien sabido, existen multitud de mtricas para medir diferentes
atributos del software, como el nmero de lneas de cdigo, nmero de puntosfuncin, complejidad ciclomtica, complejidad de datos, etc., que pueden posteriormente ser utilizadas para la realizacin de predicciones sobre futuros proyectos de desarrollo o mantenimiento, asignacin de recursos. De esta forma, el
equipo de desarrollo es capaz de conocer las posibles desviaciones en el proyecto.
Esta misma filosofa puede tambin aplicarse al proceso de pruebas y, de
hecho, tambin para l se han definido algunas mtricas. Adems de las importantes medidas de cobertura, ya discutidas en captulos anteriores, algunas mtricas son las siguientes:
1) Nmero de casos de prueba.
2) Nmero de casos de prueba/LOC
3) Nmero de casos de prueba/Nmero de requisitos
4) LOC de casos de prueba/LOC
5) Nmero de asserts/LOC
6) Nmero de casos de prueba planificados, ejecutados y pasados.
7) Coste (en unidades monetarias o en tiempo) de las diferentes actividades del proceso de pruebas.
8) Nmero de defectos encontrados en la fase de pruebas.
9) Diferentes medidas de obertura.
A continuacin se revisan algunas mtricas importantes para el proceso de
pruebas.
97
98
Proceso actual
10000
70%
700
70000
300
300000
380000
Proceso mejorado
20000
90%
900
90000
100
100000
210000
170000
10000
1700%
99
Captulo 9. REFERENCIAS
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
ISO/IEC, ISO/IEC 12207. International Standard. Software Life Cycle Processes. International Standard Organziation/International Electrotechnical Committee, 1995. Geneve.
Karlstrm D, Runeson P and Nordn S. A minimal test practice framework for
emerging software organizations. Software Testing, Verification and Reliability,
2005. 15(3): p. 145-166.
Giraudo G and Tonella P. Designing and conducting an empirical study on test
management automation. Empirical Software Engineering, 2003. 8(1): p. 59-81.
Runeson P, Andersson C and Hst M. Test processes in software product evolution -a qualitative survey on the state of practice. Journal of Software Maintenance and Evolution: Research and Practice, 2003. 15(1): p. 41-59.
Meudec C. ATGen: automatic test data generation using constraint logic programming and symbolic execution. Software Testing, Verification and Reliability, 2001. 11(2): p. 81-96.
Ball T, Hoffman D, Ruskey F, Webber R and White L. State generation and
automated class testing. Software Testing, Verification and Reliability, 2000.
10: p. 149-170.
Myers B. The Art of Software Testing. 1979: John wiley & Sons.
Cornett S. Code Coverage Analysis. 2004.
IEEE Standard for Software Unit Testing. Institute of Electrical and Electronics
Engineers, 1987.
Pressman RS. Ingeniera del Software, un enfoque prctico (3 Edicin). 1993:
McGraw-Hill.
Gallagher L, Offutt J and Cincotta A. Integration testing of object-oriented components using finite state machines. Software Testing, Verification and Reliability, 2006. 16.
Offutt AJ. A practical system for mutation testing: help for the common programmer. 12th International Conference on Testing Computer Software. 1995.
Offutt AJ, Rothermel G, Untch RH and Zapf C. An experimental determination
of sufficient mutant operators. ACM Transactions on Software Engineering and
Methodology, 1996. 5(2): p. 99-118.
Polo M, Piattini M and Tendero S. Integrating techniques and tools for testing
automation. Software Testing, Verification and Reliability, 2007. 17(1): p. 3-39.
Ma Y-S, Offutt J and Kwon YR. MuJava: an automated class mutation system.
Software Testing, Verification and Reliability, 2005. 15(2): p. 97-133.
Grindal M, Offutt AJ and Andler SF. Combination testing strategies: a survey.
Software Testing, Verification and Reliability, 2005. 15: p. 167-199.
Hoffman D, Strooper P and White L. Boundary values and automated component testing. Software Testing, Verification and Reliability, 1999. 9(1): p. 3-26.
Harrold M, Gupta R and Soffa M. A methodology for controlling the size of a
test suite. ACM Transactions on Software Engineering and Methodology, 1993.
2(3): p. 270-285.
101
19.
Jeffrey D and Gupta N. Test suite reduction with selective redundancy. International Conference on Software Maintenance. 2005. Budapest (Hungary): IEEE
Computer Society.
20.
Tallam S and . NG. A concept analysis inspired greedy algorithm for test suite
minimization. 6th ACM SIGPLAN-SIGSOFT Workshop on Program
Analysis for Software Tools and Engineering. 2005.
21.
Heimdahl M and George D. Test-Suite Reduction for Model Based Tests: Effects
on Test Quality and Implications for Testing. 19th IEEE International Conference on Automated Software Engineering. 2004.
22.
McMaster S and Memon A. Call Stack Coverage for Test Suite Reduction. 21st
IEEE International Conference on Software Maintenance. 2005. Budapest
(Hungary).
23.
Shiba T, Tsuchiya T and Kikuno T. Using artificial life techniques to generate
test cases for combinatorial testing. 28th Annual International Computer Software and Applications Conference. 2004. Hong Kong, China: IEEE Computer
Society Press.
24.
Malaiya Y. Antirandom testing: Getting the most out of black-box testing. International Sym-posium on Software Reliability Engineering (ISSRE 95). 1995.
Toulouse, France: IEEE Computer Society Press, Los Alamitos, CA.
25.
Lapierre S, Merlo E, Savard G, Antoniol G, Fiutem R and Tonella P. Automatic
Unit Test Data Generation Using Mixed-Integer Linear Programming and Execution Trees. International Conference on Software Maintenance. 1999. Oxford,
England.
26.
Daz E, Tuya J and Blanco R. Pruebas automticas de cobertura de software
mediante una herramienta basada en Bsqueda Tab. VIII Jornadas de Ingeniera del Software y Bases de Datos. 2003. Alicante, Spain.
27.
Baudry B, Fleurey F, Jzquel J-M and Traon YL. Automatic test case optimization: a bacteriologic algorithm. IEEE Software, 2005: p. 76-82.
28.
Kanstrn T. Towards a deeper understanding of test coverage. Journal of Software Maintenance and Evolution: Research and Practice, 2008. 20(1): p. 59-76.
29.
Rumbaugh J, Jacobson I and Booch G. The Unified Modelling Language Reference Manual. Segunda edicin ed, ed. A.-W.O.T. Series. 2005: AddisonWesley.
30.
Edwards SH. A framework for practical, automated black-box testing of component-based software. Software Testing, Verification and Reliability, 2001(11): p.
97-111.
31.
Ghosh S and Mathur AP. Interface mutation. Software Testing, Verification and
Reliability, 2001(11): p. 227-247.
32.
Offutt J and Xu W. Generating Test Cases for Web Services Using Data Perturbation. Workshop on Testing, Analysis and Verification of Web Services. 2004.
Boston, Massachusetts.
33.
Mogyorodi GE. What is Requirement-Based Testing? CrossTalk: The Journal of
Defense Software Engineering, 2003(march): p. 12-15.
34.
Kirani S and Tsai WT. Method sequence specification and verification of
classes. Journal of Object-Oriented Programming, 1994. 7(6): p. 28-38.
35.
Tse T and Xu Z. Test Case Generation for Class-Level Object-Oriented Testing.
9th International Software Quality Week. 1996. San Francisco, CA.
102
36.
37.
38.
39.
40.
41.
103