Vous êtes sur la page 1sur 9

Pruebas unitarias

Jos A. Maas
8.2.2013

1 Introduccin
Se dice que un programa es aceptable cuando:

hace lo que debe hacer


no hace lo que no debe hacer

Un programador jams debera entregar un programa sin haberlo probado. Quien recibe un
programa de otro, jams debera aceptarlo sin haberlo probado.
A partir de la especificacin de lo que se espera de un programa, se prepara una batera de
casos de prueba. La batera que prepara el programador le permite saber cundo ha
terminado su trabajo. La batera que prepara quien va a recibir el programa le permite saber si
puede aceptarlo o no.
Los casos de prueba se pueden escribir en papel y ejecutarlos disciplinadamente de forma
manual; pero esta estrategia slo es viable para programas pequeos. En programacin
profesional conviene automatizar las pruebas de forma que se pueden realizar muchas veces,
tanto durante el desarrollo (hasta estar satisfechos), como durante la aceptacin (para dar el
programa por correcto, como si en el futuro hay que modificar el programa (para cerciorarnos
de que no hemos roto nada que antes funcionaba).

2 JUnit
JUnit es un paquete Java para automatizar las pruebas de clases Java.
Se puede descargar de
http://sourceforge.net/projects/junit/
aunque debe decirse que viene ya instalado en los entornos de desarrollo habituales.
JUnit tiene 2 variantes principales, la llamada versin 3 y la versin 4. A continuacin se
describen ambas en paralelo, por si tiene que hacer una nueva batera o tiene que trabajar con
una antigua.
Una batera de pruebas es una clase java.

versin 3
import junit.framework.TestCase;
public class TestX
extends TestCase {
}

versin 4
import org.junit.Test;
import static junit.framework.Assert.*;
public class TestX {
}

La clase puede incluir sus variables privadas y el constructor correspondiente.


Dentro de esa clase preparamos casos de prueba, que son mtodos java:

versin 3
los casos de prueba son mtodos que
no devuelven nada void
su nombre empieza por test
no tienen argumentos ()
contiene aserciones
public void testSuma() {
assertEquals(4, 2+2);
assertEquals(2, 2+0);
assertEquals(2, 0+2);
}

versin 4
los casos de prueba son mtodos que
no devuelven nada: void
estn etiquetados como @Test
no tienen argumentos ()
contienen aserciones
@Test
public void pruebaSuma() {
assertEquals(4, 2+2);
assertEquals(2, 2+0);
assertEquals(2, 0+2);
}

3 Aserciones para probar


JUnit incluye una serie de mtodos para probar que las cosas son como esperamos. Aunque se
remite al lector a la documentacin detallada del paquete, las siguientes funciones son
bsicas:
assertEquals (X esperado, X
real)

compara un resultado esperado con el resultado obtenido,


determinando que la prueba pasa si son iguales, y que la prueba
falla si son diferentes.
Usa el mtodo equals().
Realmente el mtodo es una coleccin de mtodos para una
amplia variedad de tipos X.

assertSame(X esperado, X
real)

dem; pero usa == para determinar si es el objeto esperado.

assertFalse (boolean
resultado)

verifica que el resultado es FALSE

assertTrue (boolean
resultado)

verifica que el resultado es TRUE

assertNull (Object resultado) verifica que el resultado es "null"


assertNotNull (Object
resultado)

verifica que el resultado no es "null"

fail

sirve para detectar que estamos en un sitio del programa donde


NO deberamos estar

Consulte la documentacin: http://junit.sourceforge.net/javadoc/.

4 Excepciones
4.1 Cuando la excepcin es un error
Si salta una excepcin que no se espera, debe fallar la prueba.
A modo de ejemplo, suponga que tenemos esta funcin que a veces lanza una excepcin
private int kaos()
throws Exception {

double random = Math.random();


if (random < 0.5)
throw new Exception("Math.random() = " + random);
return 7;
}
Si entendemos que lanzar la excepcin es fallar la prueba, el mtodo de prueba queda as:
versin 3
public void testKaos()
throws Exception {
assertEquals(7, kaos());
}

versin 4
@Test
public void pruebaKaos()
throws Exception {
assertEquals(7, kaos());
}

Si lo ejecuta, ver que la prueba falla la mitad de las veces.


4.1.1

3.2 Cuando la excepcin es lo correcto


Si no salta la excepcin esperada, debe fallar la prueba.

versin 3
public void testDivision() {
try {
assertEquals(0, 2 / 0);
fail("se esperaba Exception");
} catch (Exception e) {
// es lo esperado
}
}

versin 4
@Test(expected = ArithmeticException.class)
public void testDivision()
throws Exception {
assertEquals(0, 2 / 0);
}

5 Mtodos auxiliares
versin 3
import junit.framework.TestCase;

versin 4
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.*;

import java.util.*;
import static junit.framework.Assert.*;

public class SetMiniTest_v3 extends


TestCase {
private Set s;
@Override
public void setUp() {
s = new HashSet();

public class SetMiniTest_v4 {


private Set s;
@Before
public void setUp() {
s = new HashSet();
}

}
@After
public void tearDown() {
s = null;
}

@Override
public void tearDown() {
s = null;
}

@Test
public void test0() {
assertTrue(s.isEmpty());
}

public void test0() {


assertTrue(s.isEmpty());
}

@Test
public void test1() {
assertEquals(0, s.size());
}

public void test1() {


assertEquals(0, s.size());
}

public void test2() {


s.add("x");
assertEquals(1, s.size());
}

@Test
public void test2() {
s.add("x");
assertEquals(1, s.size());
}
}

5.1 @Before
En versin 3: setUp()
JUnit lo llamar antes de lanzar cada uno de los casos de prueba.
Puede ser til cuando todos los casos de prueba requieren la misma inicializacin de variables
privadas y no basta con hacerlo en el constructor.

5.2 @After
En versin 3: tearDown()
JUnit lo llamar despus de lanzar cada uno de los casos de prueba.
Puede ser til para cerrar elementos abiertos durante la prueba que pudieran quedar en un
estado lamentable. Por ejemplo:

ficheros
conexiones Internet
conexiones a bases de datos
...

5.3 @Ignore
Es til para excluir un test de la batera y que no se ejecute.
Viene a ser lo mismo que comentar el cdigo.

5.4 @Test(timeout=100)
JUnit activa un cronmetro. Si pasados 100ms no ha terminado la prueba, suena una alarma y
falla la prueba.

6 Diseo de pruebas
Disear pruebas es un arte que ha sido objeto de estudio durante aos.
No obstante, las reglas bsicas son sencillas:

hay que prever al menos una prueba para cada funcin del sistema
hay que elegir al menos un caso "normal" de datos
cuando los datos presentan singularidades (lmites o cambio de funcionamiento por
rango) hay que probar los datos anexos a cada lmite

As, para probar una funcin que divide dos nmeros, probaremos los casos alrededor del
valor singular "0":

numerador mayor que cero, denominador mayor que cero


numerador mayor que cero, denominador menor que cero
numerador mayor que cero, denominador igual a cero
numerador menor que cero, denominador mayor que cero
numerador menor que cero, denominador menor que cero
numerador menor que cero, denominador igual a cero
numerador igual a cero, denominador mayor que cero
numerador igual a cero, denominador menor que cero
numerador igual a cero, denominador igual a cero

7 Ingls
Se incluye un sucinto glosario de terminologa inglesa relacionado con la prueba de programas.
acierto

success

batera de pruebas

test suite

caso de prueba

test case

fallo

failure

probar

to test

prueba

test

pruebas de aceptacin

acceptance test suite

repeticin de pruebas

regression testing

8 Ejemplo: conjuntos
Se adjunta una batera de pruebas para comprobar que funciona correctamente la clase
java.util.HashSet como implementacin de la clase java.util.Set.
La batera de pruebas est organizada en 6 casos de prueba cada uno centrado en una funcin
de las proporcionadas por la clase. Y en cada caso de prueba se buscan los casos singulares

conjunto vaco frente a conjunto con elementos


miembros que ya pertenecen al conjunto frente a miembros que no pertenecen al
conjunto

8.1 JUnit versin 3

import java.util.*;
import junit.framework.*;
public class SetTest_v3 extends TestCase {
private String e1= "elemento 1";
private String e2= "elemento 2";
private String e3= "elemento 3";
private String e4= "elemento 4";
private String e5= "elemento 5";
public SetTest_v3() {
// constructor
// til si hay que inicializar variables privadas
}
public void testAdd () {
Set s= new HashSet();
assertEquals(0, s.size());
assertTrue(s.add(e1));
assertEquals(1, s.size());
assertTrue(s.add(e2));
assertEquals(2, s.size());
assertFalse(s.add(e1));
assertEquals(2, s.size());
}
public void testRemove () {
Set s= new HashSet();
s.add(e1);
s.add(e2);
s.add(e3);
assertEquals(3, s.size());
assertTrue(s.remove(e2));
assertEquals(2, s.size());
assertFalse(s.remove(e2));
assertEquals(2, s.size());
assertTrue(s.remove(e1));
assertEquals(1, s.size());
assertTrue(s.remove(e3));
assertEquals(0, s.size());
}
public void testClear () {
Set s= new HashSet();
s.add(e1);
s.add(e2);
s.add(e3);
assertEquals(3, s.size());
s.clear();
assertEquals(0, s.size());
}
public void testIsEmpty () {

Set s= new HashSet();


assertTrue(s.isEmpty());
s.add(e1);
s.add(e2);
s.add(e3);
assertFalse(s.isEmpty());
s.remove(e3);
assertFalse(s.isEmpty());
s.clear();
assertTrue(s.isEmpty());
}
public void testContains () {
Set s= new HashSet();
s.add(e1);
s.add(e2);
s.add(e3);
assertTrue(s.contains(e1));
assertTrue(s.contains(e2));
assertTrue(s.contains(e3));
assertFalse(s.contains(e4));
s.add(e2);
assertTrue(s.contains(e1));
assertTrue(s.contains(e2));
assertTrue(s.contains(e3));
assertFalse(s.contains(e4));
}
public void testEquals () {
Set s1= new HashSet();
s1.add(e1);
s1.add(e2);
s1.add(e3);
Set s2= new HashSet();
assertFalse(s1.equals(s2));
s2.add(e1);
assertFalse(s1.equals(s2));
s2.add(e2);
assertFalse(s1.equals(s2));
s2.add(e3);
assertTrue(s1.equals(s2));
assertTrue(s2.equals(s1));
s2.add(e4);
assertFalse(s1.equals(s2));
assertFalse(s2.equals(s1));
}
}

8.2 JUnit versin 4


import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
import static junit.framework.Assert.*;

public class SetTest_v4


private String e1 =
private String e2 =
private String e3 =
private String e4 =
private String e5 =

{
"elemento
"elemento
"elemento
"elemento
"elemento

1";
2";
3";
4";
5";

public SetTest_v4() {
// constructor
// til si hay que inicializar variables privadas
}
@Test
public void testAdd() {
Set s = new HashSet();
assertEquals(0, s.size());
assertTrue(s.add(e1));
assertEquals(1, s.size());
assertTrue(s.add(e2));
assertEquals(2, s.size());
assertFalse(s.add(e1));
assertEquals(2, s.size());
}
@Test
public void testRemove() {
Set s = new HashSet();
s.add(e1);
s.add(e2);
s.add(e3);
assertEquals(3, s.size());
assertTrue(s.remove(e2));
assertEquals(2, s.size());
assertFalse(s.remove(e2));
assertEquals(2, s.size());
assertTrue(s.remove(e1));
assertEquals(1, s.size());
assertTrue(s.remove(e3));
assertEquals(0, s.size());
}
@Test
public void testClear() {
Set s = new HashSet();
s.add(e1);
s.add(e2);
s.add(e3);
assertEquals(3, s.size());
s.clear();
assertEquals(0, s.size());
}
@Test
public void testIsEmpty() {
Set s = new HashSet();
assertTrue(s.isEmpty());

s.add(e1);
s.add(e2);
s.add(e3);
assertFalse(s.isEmpty());
s.remove(e3);
assertFalse(s.isEmpty());
s.clear();
assertTrue(s.isEmpty());
}
@Test
public void testContains() {
Set s = new HashSet();
s.add(e1);
s.add(e2);
s.add(e3);
assertTrue(s.contains(e1));
assertTrue(s.contains(e2));
assertTrue(s.contains(e3));
assertFalse(s.contains(e4));
s.add(e2);
assertTrue(s.contains(e1));
assertTrue(s.contains(e2));
assertTrue(s.contains(e3));
assertFalse(s.contains(e4));
}
@Test
public void testEquals() {
Set s1 = new HashSet();
s1.add(e1);
s1.add(e2);
s1.add(e3);
Set s2 = new HashSet();
assertFalse(s1.equals(s2));
s2.add(e1);
assertFalse(s1.equals(s2));
s2.add(e2);
assertFalse(s1.equals(s2));
s2.add(e3);
assertTrue(s1.equals(s2));
assertTrue(s2.equals(s1));
s2.add(e4);
assertFalse(s1.equals(s2));
assertFalse(s2.equals(s1));
}
}

Vous aimerez peut-être aussi