Вы находитесь на странице: 1из 52

Técnicas de Pruebas de Caja Negra, Gris

y Blanca

Sesión 05
Ing. Henry Joe Wong Urquiza
pcsihewo@upc.edu.pe
Agenda

• Logro
• Introducción
• Clean Code
• Testeo de caja blanca
• Conclusiones
LOGRO
Logro

El estudiante al finalizar la
unidad desarrolla pruebas de
caja blanca, gris y difusas y su
implementación usando
herramientas CASE.
INTRODUCCIÓN
Definición

• Usa conocimiento interno del desarrollo del software.


• Mayormente técnica de verificación.
• Requiere de habilidades de programador.
• Enfocado en cubrir todos los caminos lógicos.
• Aplicable a los diferentes niveles de pruebas (unitarias,
integración, sistemas).
• Incapaz de detectar:
• Falta de funcionalidad (errores de omisión de código)
• Caminos inesperados
Definición

Entrada Salida
CLEAN CODE
Clean Code
Clean Code
Clean Code
Definición de Clean Code

“Sabes que estas trabajando con Código


Limpio cuando cada rutina que lees resulta ser
exactamente lo que esperabas de ella”

-Ward Cunningham

“Sabes que ves un Código Limpio cuando:


Corren todas las pruebas
• No tiene código duplicado
• Expresa todas las ideas que tiene el sistema
• Minimiza el mínimo de entidades como
clases y métodos.
-Ron Jeffries
TESTEO DE CAJA BLANCA
Introducción

URL: https://www.youtube.com/watch?v=9tJbunCrOmE
Stubs y Drivers
• Es necesario ejercitar las diferentes líneas de código
fuente.
• Un stub es una declaración de código que sustituye a la
funcionalidad de un programa.
• Ejemplo:
calcularVelocidad(int metros, int segundos) {
Auto.fijarVelocidad(20);
}

• Simular existencia de código no desarrollado.


• Un driver es el encargado de conducir la ejecución de
los comandos del código fuente.
• Ejemplo:
calcularVelocidad(100, 60);
Técnicas Comunes

• Pruebas de Caminos Básicos


• Pruebas de Flujo de Control/Cobertura
• Pruebas de Falla (“Sucias”)
Técnicas Comunes

• Pruebas de Caminos Básicos


• Pruebas de Flujo de Control/Cobertura
• Pruebas de Falla (“Sucias”)
Pruebas de Caminos Básicos

• Se aseguran de cubrir todos los caminos independientes de un módulo.


– Camino independiente :- cualquier camino en el código fuente que introduce
al menos un nuevo conjunto de comandos o una condición nueva
• Caminos se determinan dibujando un diagrama de flujo.

Rectángulo conjunto de comandos de procesamiento

condición lógica o predicado (ejemplos son if-then,


Rombo if-then-else, selection, o loop)

• El numero ciclomático es igual al número de caminos independientes.


• Mínimos casos de pruebas = numero ciclomático = predicados + 1.
Ejemplo (Monopolio)

• “Si un jugador cae en una propiedad


perteneciente a otro jugador, entonces tiene
que pagar la renta al dueño de la propiedad.
El jugador pierde el juego si no tiene dinero
para pagar la renta. Si la propiedad no le
pertenece a otro jugador y el jugador tiene
suficiente dinero para comprar la propiedad,
el o ella puede comprar la propiedad al precio
asociado a la propiedad.”
Diagrama de Flujo
• Número ciclomático
(C):
– C = predicados + 1
– C= 5+1=6

• Caminos Básicos
– 1-2-3-4-5-10
– 1-2-3-4-6-10
– 1-2-3-10
– 1-2-7-10
– 1-2-7-8-10
– 1-2-7-8-9-10
Análisis Estático por medio de
herramientas

• Todos los objetos de prueba deben tener una


estructura formal.
– Esto es especialmente importante cuando se utilizan herramientas de
pruebas.
– Con mucha frecuencia no se generan documentos formalmente.
– En la práctica, lenguajes de modelado, programación y de guión
(“scripting” ) cumplen con la regla , de la misma forma que algunos
diagramas.
• El análisis estático de un programa mediante el
uso de herramientas se desarrolla con un
esfuerzo menor que el necesario en una
inspección .
– Por lo tanto con mucha frecuencia, el análisis estático se ejecuta antes de
que tenga lugar una revisión.
Análisis Estático por medio de
herramientas

• Herramientas a utilizar: Compiladores y


herramientas de análisis (analizadores)
– Compilador .
• Detecta errores sintácticos en el código fuente de un programa.
• Crea datos de referencia del programa (por ejemplo lista e referencia cruzada,
llamada jerárquica, tabla de símbolos)
• Comprueba la consistencia entre los tipos de variables
• Detecta variables no declaradas y código inaccesible (código muerto)

– Analizador: trata de aspectos adicionales tales


como:
• Convenciones y estándares.
• Métricas de complejidad.
• Acoplamiento de objetos.
Análisis de Flujos de Control

• Propósito
– Detectar defectos causados por un desarrollo anómalo del código (ramas muertas,
código muerto, etc)
• Método
– La estructura del código se representa como un diagrama de control de flujo.
– Grafo dirigido.
– Los nodos representan sentencias o secuencias de sentencias.
– Las aristas representan las transferencias del flujo de control como decisiones y
bucles.
– Construcción mediante herramientas.
• Resultados
– Visión del conjunto del código del programa comprensible.
– Las anomalías pueden ser fácilmente detectadas, los defectos se hacen evidentes.
• Bucles abandonados por saltos.
• Ramas muertas.
• Retornos múltiples
Análisis de Flujo de Datos

• Propósito
– Detección de anomalías en el flujo de datos con la
asistencia de los diagramas de control de flujo y conjeturas
racionales respecto de las secuencias del flujo de datos
• Beneficios
– Detección fiable de anomalías en el flujo de datos.
– Se puede detectar fácilmente la localización exacta de
defectos.
– Es un buen complemento para otros métodos de pruebas.
• Desventajas
– Limitado a un rango reducido de tipos de defectos.
Análisis de Flujo de Datos

• Este es el estudio de las variables del programa


– * variable definida donde se almacena un valor en ella
– variable utilizada en donde el valor almacenado se accede
– variable no está definida antes de que sea definido o cuando se
encuentra fuera de alcance
x se define, y, z se utilizan
x=y+z
IF a > b THEN read(S)

a y b se utilizan, S se define

* definido no debe confundirse con declarado


Análisis de Flujo de Datos

n := 0
read (x) Anomalías de flujo de datos: n es
redefinido sin ser utilizado
n := 1
while x > y do Fallo de flujo de datos: y se utiliza
antes de que se ha definido
begin (primera vez alrededor del bucle)

read (y)
write( n*y)
x := x - n
end
Análisis de Flujo de Datos

El análisis de flujo de datos muestra: Este ejemplo puede ser


Para este ejemplo los valores de
dos variables son • La variable Help se encuentra fácilmente corregido
intercambiados a través de una
variable auxiliar , si no están Indefinida (undefined) cuando es
ordenados por valor Referenciada (referenced) Void MinMax (Int Min, Int Max)
Anomalìa u-r {
Int Help:
Void MinMax (Int Min, Int Max) • La variable Max se define (“defined”)
{ dos veces sin ninguna referencia if (Min > Max)
entre ambas definiciones {
Int Help:
if (Min > Max) Anomalía d-d. Help = Max
{ • El valor definido (“defined”) para la Max = Min
variable Help se vuelve indefinido Min = Help;
Max = Help (undefined) final del programa sin
Max = Min }
referencia
Help = Min; End MinMax;
Anomalìa d-u
}
End MinMax;
Las métricas y sus cálculos

• Ciertos aspectos de la calidad de un programa pueden ser medidos


utilizando métricas
– La métrica sólo tiene relevancia para el aspecto medida (considerado).
• La complejidad estática de un programa puede ser medida
– Actualmente hay aproximadamente 100 métricas diferentes disponibles.
• Métricas diferentes tratan aspectos diferentes de la complejidad del
programa
– Tamaño del programa (por ejemplo : líneas de código (“Lineas of code - LOC”)
– Estructuras de control de programa (por ejemplo “Número ciclomático)
– Estructuras de control de datos (por ejemplo : métrica de Haistead (“Haistead
Metric”)
• Es difícil comparar dos métricas diferentes, incluso cuando ambas abordan
el mismo atributo del programa.
Complejidad Ciclomática

• Complejidad Ciclomática • V (G) = a – n + 2


• V (G) = r
( La complejidad de • V (G) = c + 1
McCabe V (G)) Donde
• a : # de arcos o aristas del grafo.

– La métrica de McCabe ha •

n : # de nodos.
r : # de regiones cerradas del grafo.
sido muy popular en el • c : # de nodos de condición.

diseño de pruebas.
– Es un indicador del
número de caminos
independientes que
existen en un grafo.
¿Para que sirve V(G)?

• V (G) marca el límite mínimo de casos de


prueba para un programa.
• Cuando V (G) >10 la probabilidad de defectos
en el módulo o programa crece mucho
entonces quizás sea interesante dividir el
módulo.
¿Cuál es la complejidad
ciclomática?
1

2
3 5
Implicaciones de la Complejidad Ciclomática

• El número ciclomático puede ser utilizado como


un valor objetivo para una revisión de código.
• El número ciclomático puede ser calculado como
el número de decisiones independientes más
uno. Si las dos formas de cálculo aportan
resultados diferentes se pueden deber a :
– Ramas superfluas
– Ramas faltantes
• El número ciclomático también aporta un índice
del número de casos de prueba necesarios (para
alcanzar cobertura de decisión)
Resultado del Análisis de la Complejidad
Ciclomática

• El diagrama de flujo de control presenta el


flujo del programa y permite la detección de
“ramas muertas” y código inalcanzable.
• Las anomalías en los datos se detectan
utilizando el análisis del flujo de datos.
• Las métricas pueden ser utilizadas par evaluar
la complejidad estructural conduciendo a una
estimación del esfuerzo en pruebas a esperar.
Técnicas Comunes

• Pruebas de Caminos Básicos


• Pruebas de Flujo de Control/Cobertura
• Pruebas de Falla (“Sucias”)
Pruebas de Flujo de Control / Cobertura

• Flujo de control es representado por diagrama


de flujos.
• Pruebas enfocadas en alcanzar diferentes
tipos de cobertura:
– Cobertura de métodos
– Cobertura de comandos
– Cobertura de ramas
– Cobertura de condiciones
Ejemplo
1 int foo (int a, int b, int c, int d, float e) {
2 float e;
3 if (a == 0) {
4 return 0;
5 }
6 int x = 0;
7 if ((a==b) OR ((c == d) AND bug(a) )) {
8 x=1;
9 }
10 e = 1/x;
11 return e;
12 }
Cobertura de Métodos

• Métrica de los métodos de un módulo están cubiertos por casos de


pruebas de caja-blanca.
• Como estrategia de pruebas caja-blanca, es necesario invocar el
100% de los métodos.
• 100% de cobertura en ejemplo:
• 1 caso de prueba
• Test 1: Invocamos al método foo(0, 0, 0, 0, 0)
• El resultado esperado es 0.
Cobertura de Comandos
• Métrica que mide el porcentaje de los comandos de un módulo
cubiertos por los casos de prueba.
• Es altamente recomendable invocar el 100% de los comandos en
pruebas de caja-blanca.
• Test 1 cubre líneas 1-5 de las 12 líneas del ejemplo (42% de
cobertura de comandos).
• ¿Cómo logramos el 100% de cobertura de comandos en el
ejemplo?
• 2 casos de prueba: Test 1 y …
• Test 2: foo(1, 1, 1, 1, 1)
• El resultado esperado de Test 2 es 1.
Cobertura de Ramas

• Métrica que mide el porcentaje de los puntos


de decisión de un módulo cubiertos por los
casos de prueba.
• Puntos de decisión son comandos con
expresiones boolean de verdadero/falso.
• Puntos de decisión en ejemplo:
3 if (a == 0) {
7 if ((a==b) OR ((c == d) AND bug(a) )) {
• Debemos asegurarnos que estos predicados
sean probados como verdadero y falso
Cobertura de Ramas

• Actualmente nuestras dos pruebas solo cubren el


75% de las ramas posibles:
Línea Predicado Verdadero Falso
3 (a == 0) Test 1 Test 2
foo(0, 0, 0, 0, 0) foo(1, 1, 1, 1, 1)
return 0 return 1
7 ((a==b) OR ((c == d) AND bug(a) )) Test 2
foo(1, 1, 1, 1, 1)
return 1

• ¿Qué caso debemos añadir?


Cobertura de Ramas

• Test 3:
Línea Predicado Verdadero Falso
3 (a == 0) Test 1 Test 2
foo(0, 0, 0, 0, 0) foo(1, 1, 1, 1, 1)
return 0 return 1
7 ((a==b) OR ((c == d) AND bug(a) )) Test 2 Test 3
foo(1, 1, 1, 1, 1) foo(1, 2, 1, 2, 1)
return 1 return división
entre cero!

• Encontramos un error durante el diseño de las pruebas


Cobertura de Condiciones

• Métrica que mide el porcentaje de las expresiones sub-boolean de


un módulo cubiertas por los casos de prueba.
• Aplicable a predicados compuestos. En ejemplo:
7 if ((a==b) OR ((c == d) AND bug(a) )) {
• Pruebas aseguran de que cada sub-condición del módulo haya sido
probada.
Cobertura de Condiciones

• Actualmente nuestras dos pruebas solo cubren el 50%


de las condiciones posibles:
Línea Predicado Verdadero Falso
7 (a == b) Test 2 Test 3
foo(1, 1, x, x, x) foo(1, 2, 1, 2, 1)
return 0 return división entre cero
7 (c == d) Test 3
foo(1, 2, 1, 2, 1)
return división entre cero
7 bug(a)

• ¿Qué caso debemos añadir?


Cobertura de Condiciones

• Sabemos que bug(1) debe retornar verdadero y que


bug(>1) debe retornar falso:
Línea Predicado Verdadero Falso
7 (a == b) Test 2 Test 3
foo(1, 1, x, x, x) foo(1, 2, 1, 2, 1)
return 0 return división entre cero
7 (c == d) Test 4 Test 3
foo(1, 2, 1, 1, 1) foo(1, 2, 1, 2, 1)
return 1* return división entre cero

7 bug(a) Test 4 Test 5


foo(1, 2, 1, 1, 1) foo(3, 2, 1, 1, 1)
return 1 return 1

• Al ejecutar Test 4 tenemos un retorno de falso (0) porque hay un error en


bug(a) (bug(1) = 0 cuando debería ser igual a 1). Este caso de prueba nos
permitió descubrir el error.
Diagrama de Flujo Revisado

• Número ciclomático (C):


C= 4+1=5

• Igual que nuestros casos


de prueba.

• Es necesario escribir
métodos cortos y
mantener número
ciclomático bajo.
Técnicas Comunes

• Pruebas de Caminos Básicos


• Pruebas de Flujo de Control/Cobertura
• Pruebas de Falla (“Sucias”)
Pruebas de Falla

• Pensar como un tester de Caja Negra al


escribir pruebas de Caja Blanca.
• Cómo usuarios pueden usar aplicación.
• Analizar todas las entradas, longitudes y tipos
de variables.
• Examinar los diferentes cálculos para posibles
divisiones por cero y desbordamientos.
Niveles de Caja Blanca

Nivel Tipo Descripción

Clase Pruebas que afectan todos el constructor, las


propiedades y los métodos de una clase.

Unitarias
Módulo Pruebas que afectan un grupo de clases
relacionadas a un módulo. Basado en escenarios
funcionales.

Big Bang Prueban la mayor cantidad de módulos


desarrollados. Basado en escenarios funcionales
y cargas.
Integración Abajo-Arriba Integración de pruebas unitarias partiendo de
unidades pequeñas a más grandes.
Arriba-Abajo Integración de pruebas unitarias partiendo de
unidades grandes a más pequeñas.
Herramientas

• JUnit
• TestNG
• PHPUnit
CONCLUSIONES
Conclusiones
• Las pruebas de caja blanca (también conocidas
como pruebas de caja de cristal o pruebas estructurales) se
centran en los detalles procedimentales del software, por
lo que su diseño está fuertemente ligado al código fuente.
El testeador escoge distintos valores de entrada para
examinar cada uno de los posibles flujos de ejecución del
programa y cerciorarse de que se devuelven los valores de
salida adecuados.

Entrada Salida
Gracias!

Ing. Henry Joe Wong Urquiza


Docente UPC
E-Mail: pcsihewo@upc.edu.pe
Gtalk: hwongu@gmail.com
Facebook: facebook.com/HenryJoeWongUrquiza
Blog Personal: programandoconcafe.com
Linkedin: pe.linkedin.com/in/hwongu
Google Plus: gplus.to/hwongu
Twitter: @hwongu
Skype: hwongu

Вам также может понравиться