Prueba de programas

Anuncio
Prueba de programas
Projecte de Programació (PROP)
Prueba de programas
• Proceso de ejecución y evaluación, manual o
automática, de un sistema informático, con los
siguientes objetivos:
– Eliminación de los errores de especificación, diseño
e implementación
– Verificación de los requisitos funcionales (qué
funcionalidad falta? es lo que el usuario quería?)
– Verificación de los requisitos no funcionales
• Coste: hasta el 50% del tiempo!
2
Prueba de programas
Configuración
Software a
probar
Correcciones
Resultados Evaluación Errores
Software
Corregido
Depuración
Prueba
Tasa error
Configuración
Prueba
(Juegos Pruebas)
Modelo
De
Fiabilidad
Predicción
Fiabilidad
3
Prueba de programas
• Detección vs. Corrección (+ localización)
• Detección -> Métodos:
– Verificación formal (proving)
– Pruebas (testing)
“Program testing can be used to show the presence of bugs, but
never to show their absence” – Dijkstra
"Be careful about using the following code -- I've only proven
that it works, I haven't tested it." – Knuth
“Test your software or your users will” - Hunt & Thomas
4
Verificación formal
• Demostración formal de que el programa satisface la
especificación
Obstáculos:
• Técnicas complejas. Personal cualificado
• No garantiza la ausencia de errores de especificación
• Raramente se dispone de una especificación formal
del resto de componentes del sistema (p.ej., librerías,
entrada/salida, …)
• Uso en fragmentos críticos del programa y/o en
paralelo con el diseño
5
Pruebas
Estado entrada
Programa
(transformador de
estados)
Ideal: Batería de
ejecuciones para
probar todos los
estados de entrada
Impracticable!
Testing: Escoger un
Estado salida
subconjunto
representativo de
todos los estados
6
Pruebas (2)
• Técnica más barata y más usada
– habilidad programador
– sistemática
• No garantiza la ausencia de errores de
– especificación
– diseño
– implementación
Seguimiento manual
Prueba sistemática
• Se puede hacer más o menos exhaustiva,
según la importancia asignada a la fiabilidad
7
Pruebas (3)
Nombres:
• Test case (una prueba)
• Test suite (un juego de pruebas)
• Test plan (una colección de juegos de pruebas)
• Scenario test (una tarea que querría realizar un
usuario hipotético)
Tarea: Diseñar los anteriores para cubrir todas (???) las
posibilidades de ejecución
Entradas: Ficheros, BDs, valores parámetros/ctes., valores a
introducir interactivamente, …
Predefinir también las salidas!
8
Prueba de programas
Niveles:
• Pruebas de componentes
• Pruebas de integración
• Pruebas de sistema
• Test de aceptación
9
Pruebas de componentes
En O.O.: componente
Técnicas:
• De caja blanca
clase
– Estructura interna
• De caja negra
– funcionalidad
10
Pruebas de componentes: Caja blanca
• Necesario el acceso al código del componente
• Batería para provocar la ejecución, al menos
una vez, de cada instrucción del programa
Opciones: cada rama del “if” se ha de ejecutar
Bucles: ejecutar casos límite (ejecutar el bucle o no)
e interior
Estructuras de datos: internamente (prueba
completa según su casuística)
• Más general: cada posible camino.
• Más general: cada camino con diferentes
valores
11
Pruebas de componentes: Caja blanca (2)
{
s1;
while (c1) {
if (c2) s2 else s3;
s4;
}
if (c3) s5 else s6;
}
s1
inici
c3
c1
s5
s6
c2
s2
s3
s4
final
Método basis set :
1) Escoger un conjunto de caminos que cubren
todos los arcos
2) Poner un test case para cada camino
12
Pruebas de componentes: Caja blanca (3)
Método dataflow:
• Localizar qué puntos en el programa dan valor a una
variable y cuáles la consumen
• Para cada variable x definir conjuntos de
instrucciones Def(x) (donde se asigna) y Use(x)
(donde se lee)
• Para cada instrucción s, definir Def(s) y Use(s) a
partir de los Def(x) y Use(x)
• Definir cadenas DU (Def-Use):
(x,s1,s2) si x está en Def(s1) y en Use(s2) y
la definición de x en s1 aún es válida en s2
• Necesario cubrir al menos una vez cada cadena DU
13
Pruebas de componentes: Caja negra
• Complementario y normalmente posterior a caja blanca
• Se usa sólo la interficie del componente
• Tipos error:
–
–
–
–
–
funcionalidades incorrectas o no previstas
errores de interficie
errores de E.D. externas
errores de funcionamiento
errores de inicialización o terminación
• Juegos de prueba mínimamente completos:
– Dividir el dominio de cada variable en “clases de equivalencia”
(comportamiento uniforme - subjetivo…)
Ej: x Є N
{0}
{x | 0 < x < 7}
{x | x ≥ 7}
– Escoger un representante de cada clase
– Test suite: todas las combinaciones de representantes (conjunto
cociente)
• Atención a los casos extremos / valores frontera
14
Concurrencia / tiempo real
Necesario comprobar, además:
• Secuenciación temporal (timing) de los datos
• Paralelismo / interacción entre procesos
• Problemas de bloqueo y competencia entre procesos/recursos
• Reacción ante eventos externos/ relación con el entorno de
ejecución
• Reparto de carga
• Recuperación de errores (hardware, otros programas, ...)
• Sistemas operativos, sistemas de fabricación, redes, …
• Código de control de errores llega a ser el 70%
15
Estrategia de prueba
Etapas:
• Planificación prueba: orden de prueba de las piezas
• Diseño: casos a probar y resultados esperados
• Prueba: ejecución
• Obtención de resultados
• Evaluación
16
Pruebas de integración
• Se prueban interacciones entre componentes
A nivel de test: comp. no probado <-> comp. no construido
• Integración incremental: No “Big Bang”
• También “caja blanca + caja negra”
• Enfoques:
– Ascendente: Drivers
Programa que prueba un componente de “nivel más
bajo”
– Descendente: Stubs
Programa que permite probar otro “de nivel más alto”
(Los niveles vienen marcados por los distintos tipos de
relaciones entre componentes utilizadas)
17
Pruebas de integración: Drivers
Presentar
resultados
Leer
datos de test
Driver
Retornar
resultados
Invocar
métodos
Clase
a probar
Atención:
Se piden drivers
interactivos!!
Que no haga falta
recompilar para
probar con nuevos
datos!
Entrada por
teclado o
ficheros de texto
18
plano!
Pruebas de integración: Stubs
Stub: representa una clase C con
interficie conocida pero aún no
ejecutable
Clase
a probar
Retornar
resultados
Invocar
métodos
Stub
Implementa una versión simple de la
funcionalidad final de C
P.ej.
• Escribir “se ha llamado el método
m de C con parámetros x”
• Retornar datos constantes
• ...
19
Caso particular: Clases abstractas
C: Clase
abstracta
Stub
concreto
El stub concreto implementa los
métodos abstractos de C de manera
simple.
Permite crear instancias de C para
probar los métodos implementados en
C (eventualmente por medio de otros
stubs y drivers)
20
Pruebas de integración
• Enfoques:
– Ascendente: Drivers
-) El programa no existe hasta el final
+) Los componentes de nivel más bajo pasan más pruebas
– Descendente (profundidad/anchura): Stubs
-) Construcción de stubs
+) Ya tenemos el programa entero – solapamiento con pruebas
de validación
– Métodos híbridos: Sandwich Testing
Si conviene comenzar probando los componentes más críticos:
• Reutilización
• Visibilidad del producto
• Grado de acoplamiento y uso de los distintos componentes
• Adquisición de datos a partir del usuario
21
Pruebas de integración
• Stubs, drivers y test suites son el soporte
(scaffolding) para construir nuestro sistema
• Serán retirados al final
• Pero pasar tiempo diseñándolos NO es tiempo perdido
• Escribe mucho más código que el que irá en la versión
final
22
Pruebas
Consejos:
• Prueba pronto: ahorrarás tiempo y €
• Escribe tests que prueben propiedades bien
definidas
• Escribe tests que se entiendan
• Documenta los tests (formulario!)
• Uso de herramientas: JUnit
• Escribe los tests antes que el código
• Escribe mucho código para hacer testing
23
Descripció dels jocs de proves
Cada fitxer executable del segon lliurament ha d’anar acompanyat d’un text
que descrigui:
•Objecte de la prova: casos d'ús i classes, o integració de conjunts, provats
anteriorment, que es proven
•Altres elements integrats a la prova: classes ja provades o que s'han
provat d'alguna altra manera –reutilitzats, etc.– integrades en aquest
executable (si n'hi ha)
•Drivers construïts per aquesta prova i integrats en l'executable, amb
descripció de la seva missió (si n'hi ha)
•Stubs construïts per aquesta prova i integrats en l'executable, amb
descripció de la seva missió (si n'hi ha)
•Fitxers de dades necessaris: nom dels fitxers de dades, si n'hi ha, i tal cas
les classes que s'emmagatzemen en cadascun
•Valors estudiats: amb quins valors es prova i quina missió tenen, aquí és
on s'hauria de parlar de caixa blanca o negra, conjunts de dades de
comportament homogeni, etc.
•Efectes estudiats: funcionalitats com ara vistes, moviments per la pantalla,
selecció en llistes, etc. que no són dades concretes
•Operativa: petit manual o descripció del funcionament de l'executable, molt
bàsica
24
Regresión
• Partes que funcionaban dejan de funcionar
– Cuando añadimos funcionalidad
– Cuando rediseñamos (“mejoramos”) una parte
• Bugs supuestamente eliminados reaparecen
(regression bugs)
• Especialmente, en tareas de mantenimiento
25
Regresión (2)
• Test de regresión:
Ejecutar todas las baterías ya superadas en
etapas anteriores cuando introducimos cambios
• … en cada “build”, o cada noche/semana
• Importante:
añadir test cases para cada bug ya eliminado!
• Herramientas semi-automáticas para testing
(Junit, …)
26
Junit (1)
• Conjunto de bibliotecas creadas por Erich Gamma y Kent Beck
que son utilizadas en programación para hacer pruebas unitarias
de aplicaciones Java. (wikipedia)
• JUnit es un conjunto de clases (framework) que permite realizar
la ejecución de clases Java de manera controlada, para poder
evaluar si el funcionamiento de cada uno de los métodos de la
clase se comporta como se espera. Es decir, en función de algún
valor de entrada se evalúa el valor de retorno esperado; si la
clase cumple con la especificación, entonces JUnit devolverá que
el método de la clase pasó exitosamente la prueba; en caso de
que el valor esperado sea diferente al que regresó el método
durante la ejecución, JUnit devolverá un fallo en el método
correspondiente.
27
JUnit (2)
• JUnit es también un medio de controlar las pruebas de
regresión, necesarias cuando una parte del código ha sido
modificado y se desea ver que el nuevo código cumple con los
requerimientos anteriores y que no se ha alterado su
funcionalidad después de la nueva modificación.
• El propio framework incluye formas de ver los resultados
(runners) que pueden ser en modo texto, gráfico (AWT o Swing)
o como tarea en Ant.
• En la actualidad las herramientas de desarrollo como NetBeans y
Eclipse cuentan con plug-ins que permiten que la generación de
las plantillas necesarias para la creación de las pruebas de una
clase Java se realice de manera automática, facilitando al
programador enfocarse en la prueba y el resultado esperado, y
dejando a la herramienta la creación de las clases que permiten
coordinar las pruebas.
28
Pruebas de validación/ de sistema
Instrumentos
• Producto completo
• Especificación de requerimientos funcionales y
operativos
• Documentación de usuario
Pruebas de sistema (entorno real):
• Seguridad
• Recuperación (caída de sistema)
• Potencia (condiciones extremas: volumen, frecuencia,
horas punta, número de usuarios)
• Eficiencia (tiempo de respuesta, consumo recursos, …)
• Interacción con otro software
• Usabilidad…
29
Test de aceptación
• Realizado por el cliente/usuario final
• Pruebas de aceptación controladas:
– alfa: con presencia del programador
– beta: sin presencia del programador
Hasta cuándo probar?
• Hasta que se acaba el tiempo o el dinero!
• Cuando #errores detectados/unidad de tiempo tiende a 0
• Producto final = Versión pre-alfa del siguiente producto
30
Depuración de errores (debugging)
Etapas para cada error:
• Detección (síntomas)
• Localización (causas)
• Determinación de la fase en que se ha producido
(especificación-diseño-implementación)
• Evaluación de la gravedad (leve-grave-crítico) y del
coste de corrección
• Corrección
• Comprobación (-> tests de regresión)
31
Depuración de errores (debugging) (2)
Algunas heurísticas:
• Brute Force Approach: Seguimiento sistemático del
funcionamiento del programa
• Backtracking: Retroceder desde el punto donde se
ha detectado el síntoma. Problema: efecto lateral?
• Localizar puntos del programa donde se pudieron
producir las causas del síntoma: Mirar variables que
intervienen y asignaciones de éstas
• Comprobación de los contratos de las llamadas
(pre y postcondiciones)
• Assert de Java / librería InOut de PRAP
• Regresión: arreglar un bug ha generado otros?
32
Java – Assert statement
assert Expresión_booleana
assert Expresión_booleana: Expresion_textual
AssertionError [“ “+Expresion_textual]
• Las aserciones se usan para afirmar o comprobar
suposiciones sobre el estado del programa que
asumimos ciertas: situaciones imposibles,
precondiciones, invariantes, postcondiciones,...
• Su checking se puede habilitar/deshabilitar (de
forma selectiva o no para clases/packages).
• En principio se usan durante el desarrollo y se
deshabilitan durante la explotación
• OJO con efectos laterales de Expresion_booleana
33
Experiencia
Consejo:
• Un error ha de servir para evitar repetirlo
• Reflexionad: por qué he cometido este error?
• Compartidlo con el resto del grupo!
“Experience is the name everyone gives to his mistakes” -
Oscar Wilde, Lady Windemere's Fan
“Human beings, who are almost unique in having the ability
to learn from the experience of others, are also
remarkable for their apparent disinclination to do so” Douglas Adams, Last Chance to See
“Experience is what you get when you don’t get what you
want” - Dan Stanford
34
Excepciones
Public boolean leeDatos (File fichero) throws ExcepFichero1, IOException,…
{…
if (linea==null) throw new ExcepFichero1(fichero.getName());
…}
Public class ExcepFichero1 extends Exception
{
public string filename;
public ExcepFichero1 (string nombre)
{
super(“Error en fichero” + nombre + “, formato incorrecto”);
filename= nombre;
}
}
Al invocar un método con excepciones en su “throws” puedes:
• Capturar (Catch) la excepción y gestionarla
• Capturar la excepción y mapearla en una de tus excepciones
• Declarar la excepción en tu “throws” y pasarla (pila de llamadas)35
Excepciones
• Gestionan condiciones inusuales/inesperadas durante la
ejecución:
– Problemas de estado interno de un objeto (valores de variables
inconsistentes, …)
– Errores en manipulación de objetos o datos (ficheros, direcciones de
red, …)
– Violación de contrato básico del objeto (leer datos de una stream ya
cerrada, …)
• Forma limpia de chequear errores sin llenar el flujo de código con
chequeos.
• Hacen que las condiciones de error que un método puede señalar
sean parte explícita de la cabecera de ese método (su contrato).
• La lista de excepciones puede ser:
– vista por el programador
– chequeada por el compilador
– preservada por las clases que heredan y redefinen el método
(compatible: lanzar las mismas excepciones o menos, nunca más, ni
nuevos tipos, ni más generales que en la superclase)
36
Descargar