El objetivo de esta practica es
comprender cómo se realizan pruebas unitarias de manera
automática utilizando el framework JUnit.
JUnit
JUnit es un framework orientado a la realización de pruebas
unitarias en Java. La idea en JUnit es crear una clase de prueba por
cada clase que queramos probar. Esta clase de prueba se encarga de:
- Instanciar clase a probar
- Preparar el caso de prueba (fixture)
- Invocar metodos sobre clase a probar
- Verificar que los metodos entregan una salida adecuada con
respecto a una entrada particular.
Una clase de pruebas hereda siempre de la clase
TestCase
y contiene un conjunto de metodos que corresponden a las pruebas que se
van a realizar. En general, por cada metodo de la clase que queramos
probar, vamos a tener un metodo en la clase de prueba. El metodo de la
clase de prueba tiene el mismo nombre que el de la clase probada pero
con el prefijo
test.
También hay que notar que se recomienda que las clases de prueba
se pongan en package con el mismo nombre pero que inicie por test.
Por ejemplo:
Clase a probar |
Clase de prueba |
package
ejemplo;
public class Entero
{
int m_valor;
public void setValor(int
valor)
{
m_valor = valor;
}
public int getValor()
{
return m_valor;
}
public int suma(Entero otro)
{
m_valor = m_valor+otro.getValor();
return m_valor;
}
} |
package test.ejemplo;
import ejemplo.Entero;
import junit.framework.*;
public class EnteroTest extends TestCase
{
private Entero m_entero;
/**
* Inicialización de la prueba
*/
protected void setUp() throws Exception
{
m_entero = new Entero();
m_entero.setValor(5);
}
/**
* Prueba de setValor
*/
public void testSetValor()
{
m_entero.setValor(8);
assertEquals(m_entero.getValor(),8);
}
/**
* Prueba de getValor
*/
public void testGetValor()
{
assertEquals(m_entero.getValor(),5);
}
/**
* Prueba de suma
*/
public void testSuma()
{
Entero e1 = new Entero();
e1.setValor(4);
m_entero.suma(e1);
assertEquals(m_entero.getValor(),9);
}
public static
Test suite()
{
TestSuite suite = new TestSuite(EnteroTest.class);
return suite;
}
} |
Hay que subrayar que la preparación de caso de prueba (o
fixture) se realiza en el metodo llamado
setUp().
Este metodo siempre es invocado (de forma
automática) antes de que se invoque uno de los metodos de la
clase de
prueba.
Por otro lado, dentro de las pruebas, se usa el metodo
assertEquals
para verificar que dos valores sean iguales. La clase TestCase provee
distintos metodos para comprobar que dos valores sean iguales,
distintos o bien que un objeto es nulo o no.
Normalmente, cada test se realiza creando una instancia de la clase de
prueba y pasandole en una cadena el nombre del metodo correspondiente a
la prueba que se quiere realizar, por ejemplo:
TestCase test = new EnteroTest("testSuma");
test.run(); |
Sin embargo esto es complicado cuando se tiene un numero elevado de
pruebas a realizar. Para ello se utiliza el concepto de
suite. Una suite corresponde a un
conjunto de tests que se realizan de manera secuencial. La
creación de una suite es simplificada con la clase
TestSuite.
En el ejemplo anterior, el metodo suite (notese que es estático)
recibe cómo parametro el nombre de la clase de prueba. Cuando
esto ocurre la suite de pruebas va a incluir todos los metodos de
prueba que empiezen por test, de ahi la importancia de seguir la
convención de nombrado.
NOTA: Al compilar y
ejecutar es necesario hacerlo desde la línea de comando.
Una vez que hemos hecho la prueba, es posible complilarla y ejecutarla
de la manera siguiente desde la línea de comando:
$javac
-classpath junit.jar -d build/ src/ejemplo/*.java
src/test/ejemplo/*.java
$java -cp build/:junit.jar junit.textui.TestRunner
test.ejemplo.EnteroTest
...
Time: 0.019
OK (3 tests)
|
Ejercicio 1: Prueba simple
Codificar la clase Entero y su clase de prueba. Efectuar las pruebas y
verificar que el resultado sea correcto.
- Qué pasa si remplazas junit.textui.TestRunner por
junit.swingui.TestRunner ?
- Qué pasa si modificas la clase Entero en el metodo
suma y cambias la suma por una resta y luego re-ejecutas las pruebas?
En este primer ejercicio, te puede parecer exagerado que la clase de
prueba sea más grande que la clase probada, sin embargo eso no
es siempre el caso, como veremos en el ejemplo siguiente.
Ejercicio 2: Integración de Ant y Junit
Introduce la información siguiente en tu script ant.
Dentro de
target init:
<property
name="junitreports.dir" value="${doc.dir}/junitreports"/> |
Dentro de
target prepare:
<mkdir
dir="${junitreports.dir}"/> |
Dentro de
target clean:
<delete
dir="${junitreports.dir}"/> |
<target
name="test" depends="compile">
<junit printsummary="true" >
<formatter type="xml"/>
<test
name="${maintestclass}"/>
<classpath>
<pathelement location="${build.dir}" />
</classpath>
</junit>
<junitreport todir="${junitreports.dir}">
<fileset dir=".">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" todir="${junitreports.dir}/html"/>
</junitreport>
</target> |
Ejecuta el target
test y ahora
apunta tu navegador al directorio
doc/junitreports/html