Laboratorio de Programación Documentación

Anuncio
Laboratorio de Programación
Documentación
Pruebas Unitarias
Dpto. de Ingeniería de Sistemas Telemáticos
http://www.lab.dit.upm.es/~lprg/
febrero 2010
Documentación
Documentación y Pruebas
2
1
¿Qué es documentar?
Documentar el código de un programa es añadir
suficiente información como para explicar lo que
hace, punto por punto, de forma que no sólo los
ordenadores sepan qué hacer, sino que además los
humanos entiendan qué están haciendo y por qué.
No se trata sólo de rematar el trabajo, sino que
responde a necesidades reales que pueden aparecer
en el futuro:
Extender el programa con nuevas funcionalidades
Adaptarlo a un nuevo escenario
Documentación y Pruebas
3
¿Qué hay que documentar?
Reglas básicas:
Documentar/explicar aquello que no es evidente
No repetir lo que se hace, sino explicar por qué se hace así
Y esto se traduce en:
¿de qué se encarga una clase? ¿un paquete?
¿qué hace un método?
¿cuál es el uso esperado de un método?
¿para qué se usa una variable?
¿cuál es el uso esperado de una variable?
¿qué algoritmo estamos usando? ¿de dónde lo hemos sacado?
¿qué limitaciones tiene el algoritmo? ¿... la implementación?
¿qué se debería mejorar ... si hubiera tiempo?
Documentación y Pruebas
4
2
Tipos de comentarios
javadoc
Delimitados por “/**” y “*/”
Pueden abarcar varias líneas (que quizás comiencen por “*”)
Permiten generar documentación externa al programa
una línea
Comienzan con “//” y terminan con la línea
Para documentar código que no se desea que aparezca en
documentación externa
Pueden utilizarse varios seguidos
tipo C
Comienzan con “/*” y terminan con “*/”
Pueden abarcar varias líneas
Permiten “eliminar” código que no queremos olvidar del todo
Documentación y Pruebas
5
¿Cuándo documentar?
Por obligación (javadoc)
al principio de cada clase
al principio de cada método
antes de cada variable de clase
Por conveniencia (una línea)
al principio de un fragmento de código no evidente
a lo largo de los bucles
Por si acaso (una línea)
siempre que se haga algo raro
siempre que el código no sea evidente
Documentación y Pruebas
6
3
Javadoc
Es una herramienta del kit de desarrollo que permite
generar documentación Web a partir del código
Más que ayudar a comprender el código, se centra en
la interfaz (API – Application Programming Interfaz)
de las clases y paquetes Java
Javadoc exige unos comentarios especiales:
/**
* Parte descriptiva
* Que puede abarcar varias frases o párrafos
*
* @etiqueta texto específico para la etiqueta
*/
Documentación y Pruebas
7
Javadoc – Clases e Interfaces
Al menos, deben usarse las etiquetas
@author
@version
Etiquetas posibles
@author
Nombre del autor
@version
Identificació de versión y fecha
@see
Referencia a otras clases y métodos
@since
Indica desde qué versión o fecha existe la clase o
interfaz en el paquete
@deprecated
Esta clase no debería usarse pues puede
desaparecer en próximas versiones
Documentación y Pruebas
8
4
Javadoc – Constructores y Métodos
Al menos, deben usarse las etiquetas
@param – una por argumento de entrada
@return – si el método no es void
@exception – una por tipo de Exception que pueda lanzar
Etiquetas posibles
@param
Nombre del parámetro
@return
Descripción de su significado y uso
Descripción de lo que se devuelve
@exception
Nombre de la excepción
Excepciones que pueden lanzarse
@since
Indica desde qué versión o fecha existe este constructor o
método en la clase
@deprecated
Este método no debería usarse pues puede desaparecer en
próximas versiones
Documentación y Pruebas
9
Javadoc – Atributos
No hay ninguna etiqueta obligatoria
Etiquetas posibles
@since
Indica desde qué versión o fecha existe este atributo en la
clase
@deprecated
Este atributo no debería usarse pues puede desaparecer en
próximas versiones
Documentación y Pruebas
10
5
Ejecución de Javadoc
<Directorio_Instalación>\javadoc Programa.java
Múltiples opciones (entre ellas):
usage: javadoc [options] [packagenames] [sourcefiles] [classnames] [@files]
-public Show only public classes and members
-protected Show protected/public classes and members (default)
-package Show package/protected/public classes and members
-private Show all classes and members
-sourcepath <pathlist> Specify where to find source files
-classpath <pathlist> Specify where to find user class files
-verbose Output messages about what Javadoc is doing
-d <directory> Destination directory for output files
-version Include @version paragraphs
-author Include @author paragraphs
-docfilessubdirs Recursively copy doc-file subdirectories
-splitindex Split index into one file per letter
-windowtitle <text> Browser window title for the documenation
-doctitle <html-code> Include title for the overview page
-header <html-code> Include header text for each page
-footer <html-code> Include footer text for each page
-bottom <html-code> Include bottom text for each page
Documentación y Pruebas
11
Referencias
How to Write Doc Comments for the Javadoc Tool
http://java.sun.com/j2se/javadoc/writingdoccomments/
Ejemplo de Javadoc
http://java.sun.com/javase/6/docs/api/
Documentación y Pruebas
12
6
Pruebas Unitarias
Documentación y Pruebas
13
Objetivo
El objetivo único de las pruebas es encontrar
errores en el código
antes de que aparezcan en ejecución
Una batería de pruebas es tanto mejor cuanto
menos errores pasan desapercibidos
Un programa es aceptable cuando:
Hace lo que se acordó que debería hacer en las
especificaciones
No hace lo que no debe hacer
Jamás debería entregarase un programa sin
haberlo probado
Documentación y Pruebas
14
7
Enfoque psicológico
El que desarrolla
comprueba que el programa funciona
con todo lo que se le ocurre que debe
funcionar
El que prueba
comprueba que el programa no falla
con todo lo que se le ocurre que puede
fallar
Documentación y Pruebas
15
Tipos de prueba
Pruebas de caja blanca: analizar el propio código (pruebas
estructurales)
Pruebas de caja negra: sin ver el código, probar la funcionalidad
según especificaciones (pruebas funcionales)
Pruebas de integración: probar cómo funciona el sistema
completo, compuesto por módulos distintos.
Pruebas de aceptación: realizadas el cliente para ver si se le
entrega lo que pidió.
Pruebas de regresión: tras añadir algo nuevo, para ver que no se
ha descabalado la funcionalidad que ya había.
Pruebas de robustez o solidez, de aguante, de prestaciones, etc.
Documentación y Pruebas
16
8
Caja Negra: Casos de Prueba
¿Qué hay que probar?
Todo lo que dice la especificación
Manual
Instrucciones
Documentación adicional
Hasta completar el 100% de cobertura
Documentación y Pruebas
17
Caja Negra: Datos de Prueba
Divida el espacio de pruebas en clases de equivalencia
conjuntos de datos con comportamientos similares
Elija un dato “normal” de una clase de equivalencia
Pruebe con todos los datos “frontera” (valores
extremos)
Añada aquellos casos donde piense que el
programador puede haberse equivocado
Pruebe todas las combinaciones de
{datos x comportamiento}
Documentación y Pruebas
18
9
Caja Negra: Ejemplo
Probar un método de ordenación de un array
Input: 2 10 6 3 8 7 9 5 4 1
Output: 1 2 3 4 5 6 7 8 9 10
¿Qué hay que probar?
que todos los datos están en orden ascendente
for (int i= 1; i < n; i++)
assert (dato[i-1] <= dato[i]);
¿Con qué datos probar?
Casos normales: N datos
10 datos al azar
Casos singulares: 0 y 1 datos
“sospechas”
Elementos ya ordenados: 1 2 3 4 5 6 7 8 9 10
Elementos ordenados al revés: 10 9 8 7 6 5 4 3 2 1
Documentación y Pruebas
19
Caja Blanca: Casos de Prueba
¿Qué hay que probar?
Ejecutar, al menos, una vez cada sentencia
cobertura de sentencias
Ejecutar al menos una vez cada condición con resultado cierto y
falso
cobertura de ramas
Hasta completar el 100% del código
if (...)
Si T, si F
switch (...)
Cada ‘case’ + default
Cobertura de bucles
for -> 3 pruebas: 0 veces, 1 vez, n>1 veces
repeat -> 2 pruebas: 1 vez, n>1 veces
while-> 3 pruebas: 0 veces, 1 vez, n>1 veces
Documentación y Pruebas
20
10
JUnit: Pruebas sistemáticas
Prueba unitaria: una prueba individual de un método o clase.
Prueba unitaria ad-hoc: por ejemplo, cuando creamos un objeto de
cierta clase con BlueJ e invocamos manualmente un método del mismo
con distintas entradas para ver si funciona.
Sin embargo, con este tipo de pruebas no se puede trabajar eficiente y
sistemáticamente.
Cada vez que cambiamos algo en el método o clase tendríamos que
volver a pasar todas las pruebas para asegurarnos de que “nada se ha
descabalado”. Es decir, realizar pruebas de regresión.
Para ello, vendría muy bien algo que nos permitiera definir
sistemáticamente una serie de pruebas y ejecutarlas
automáticamente, tantas veces como necesitáramos.
JUNIT nos permite hacer esto (www.junit.org)
Documentación y Pruebas
21
JUnit: Procedimiento
Antes de implementar una determinada funcionalidad, piensa cómo deberías
probarla para verificar que se comporta correctamente. Esto permite
desarrollar la funcionalidad teniendo las ideas muy claras de lo que debería
hacer.
Escribe el código que implementa la funcionalidad deseada.
Escribe el código de las pruebas inmediatamente después.
Ejecuta las pruebas que hiciste.
Corrige la unidad de código que implementa la funcionalidad deseada hasta que
pase todas y cada una de las pruebas.
Al añadir una nueva funcionalidad, repite el ciclo: piensa en cómo probarla,
codifica la funcionalidad, codifica las pruebas, ejecuta todas las pruebas que
hiciste (nuevas y viejas). No sigas hasta que el código pase absolutamente todas
las pruebas.
Así una y otra vez para cada nueva funcionalidad que implementes. Lo vemos con
un ejemplo.
Documentación y Pruebas
22
11
JUnit: Ejemplo (1)
Desarrollar un método estático que tome un array de enteros como
argumento y devuelva el mayor valor encontrado en el array.
public class MayorNumero {
/**
* Devuelve el elemento de mayor valor de una lista
* @param
list
Un array de enteros
* @return
El entero de mayor valor de la lista
*/
public static int mayorNumero(int lista[]) {
return 0; // para que compile, hasta que
//desarrollemos el método
}
}
Documentación y Pruebas
23
JUnit: Ejemplo (2)
¿Qué pruebas pueden hacerse?
Caso normal: array con valores cualesquiera
[3, 7, 9, 8] -> 9
El mayor número se encuentra al principio o al final de la lista
[9, 7, 8] -> 9
[8, 7, 9] -> 9
El mayor número está duplicado en el array
[9, 7, 9, 8] -> 9
Sólo hay un elemento en el array
[7] -> 7
Array compuesto por números negativos
[-4, -6, -7, -22] -> -4
Documentación y Pruebas
24
12
JUnit: Ejemplo (3)
Escribimos el código del método:
/**
* Devuelve el elemento de mayor valor de una lista
*
* @param list
Un array de enteros
* @return
El entero de mayor valor de la lista
*/
public static int mayorNumero(int lista[]) {
int indice, max = Integer.MAX_VALUE;
for (indice = 0; indice < lista.length-1; indice++) {
if (lista[indice] > max) {
max = lista[indice];
}
}
return max;
}
Documentación y Pruebas
25
JUnit: Ejemplo (4)
Escribimos el código de las pruebas:
import junit.framework.*;
public class TestMayorNumero extends TestCase {
public TestMayorNumero() {
}
public void testSimple() {
assertEquals(9, MayorNumero.mayorNumero(new int[] {3, 7, 9, 8}));
}
public void testOrden() {
assertEquals(9, MayorNumero.mayorNumero(new int[] {9, 7, 8}));
assertEquals(9, MayorNumero.mayorNumero(new int[] {7, 9, 8}));
assertEquals(9, MayorNumero.mayorNumero(new int[] {7, 8, 9}));
}
public void testDuplicados() {
assertEquals(9, MayorNumero.mayorNumero(new int[] {9, 7, 9, 8}));
}
public void testSoloUno() {
assertEquals(7, MayorNumero.mayorNumero(new int[] {7}));
}
public void testTodosNegativos() {
assertEquals(-4, MayorNumero.mayorNumero(new int[] {-4, -6, -7, 22}));
}
public static void main (String args[]) {
junit.textui.TestRunner.run(TestMayorNumero.class);
}
}
Documentación y Pruebas
26
13
JUnit: Ejemplo (4)
Fallos detectados:
Error de concepto: MAX_VALUE por MIN_VALUE
Valor frontera en un bucle
Error en la propia definición de las pruebas
Documentación y Pruebas
27
JUnit
Marco para desarrollar pruebas unitarias
Pasos:
Importar las clases de JUNIT necesarias
Definir la clase de pruebas:
Debe extender la clase “TestCase”
Definir los métodos de prueba
Deben comenzar por “test”
Serán ejecutados automáticamente por JUNIT
Definir un main o ejecutar desde un IDE
junit.textui.TestRunner.run(<clase>)
Documentación y Pruebas
28
14
Junit: comprobaciones
assertEquals (valor_esperado, valor_real);
Los valores pueden ser de cualquier tipo
Si son arrays, no se comprueban elemento a elemento, sólo la referencia
assertTrue (condición_booleana)
assertFalse (condición_booleana)
assertSame (Objeto esperado, Objeto real)
Comprueba que son la misma referencia
assertNotSame (Objeto esperato, Objeto obtenido)
Comprueba que son referencias distintas
assertNull (Objeto)
Comprueba que el objeto es Null
assertNotNull (Objeto objeto)
Comprueba que el objeto no es Null
fail (string Mensaje)
Imprime el mensaje y falla
Útil para comprobar que se capturan excepciones
Documentación y Pruebas
29
Junit: Uso de las comprobaciones
En una función de prueba (“testXXX”), se pueden poner tantos métodos
de comprobación como sean necesarios para implementar el caso de
prueba concreto.
A la hora de ejecutar la función prueba (“testXXX”), en cuanto falle uno
de los métodos de comprobación se para la ejecución. No se ejecutan el
resto de métodos de comprobación tras el que falló.
En ese caso, antes de seguir es MUY aconsejable corregir el fallo que
se ha producido.
En general hay que comprobar que un método lanza todas las
excepciones que se han declarado en el mismo cuando debe. Y que no las
lanza cuando no hay motivo para ello. Esta es la utilidad del método fail.
public void testExcepcionOrdenarListaNula( ) {
try {
ordena_lista(null);
fail(“Debería haber lanzado una excepción”);
} catch (RuntimeException e) { }
}
Documentación y Pruebas
30
15
Junit: setUp & tearDown
Se pueden poner métodos para envolver las pruebas:
public void setUp() { ...; }
public void tearDown() { ...; }
setUp()
setUp()
setUp()
test001()
test002()
test003()
tearDown()
tearDown()
tearDown()
Documentación y Pruebas
31
16
Descargar