Está en la página 1de 16

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 Descripción de su significado y uso


@return 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