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:
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: Checkout y realización de pruebas sobre
la arquitectura
En esta segunda iteración de la arquitectura, se incluye un
ejemplo de realización de prueba de manera automática.
Para probarlo vamos a hacer un checkout.
NOTA:
probablemente tengas que hacer un checkout de tu propio proyecto ya que
el trunk que se muestra a continuación ya no es accesible.
Paso 1:
$svn
checkout svn://www.humbertocervantes.net/proyecto/trunk
|
Una vez que ha terminado el checkout, vamos a realizar las pruebas
$ant
test
test:
[junit] Running
test.mx.uam.ingsoft.pluginadmin.AdministradorPluginsImplTest
[junit] Tests run: 7, Failures: 0, Errors: 0, Time elapsed: 2.542 sec
[junit] Testsuite:
test.mx.uam.ingsoft.pluginadmin.AdministradorPluginsImplTest
[junit] Tests run: 7, Failures: 0, Errors: 0, Time
elapsed: 2.542 sec
[junit] ------------- Standard Output ---------------
....
[junit] ------------- ----------------
---------------
[junit] Testcase: testAdministradorPluginsImpl took
0.03 sec
[junit] Testcase: testGetListaPlugins took 0.01 sec
[junit] Testcase: testGetPlugin took 0.067 sec
[junit] Testcase: testInstalaPlugin took 0.03 sec
[junit] Testcase: testRetiraPlugin took 0.024 sec
[junit] Testcase: testActivaPlugin took 2.31 sec
[junit] Testcase: testDesactivaPlugin took 0.056 sec
BUILD SUCCESSFUL
Total time: 5 seconds
|
Paso 2:
Checa la case
test.mx.uam.ingsoft.pluginadmin.AdministradorPluginsImplTest
y comparala con la clase que está probando:
mx.uam.ingsoft.pluginadmin.AdministradorPluginsImpl
Paso 3:
Para probar el administrador de plugins, es necesario instalar un
plug-in. Sin embargo, si recuerdas, al ser inicializado, un plug-in
recibe un
Contexto.
Dentro de la arquitectura, el contexto está implementado por el
núcleo de la aplicación, así que no es factible
instanciar toda la aplicación para hacer las pruebas. Por ello
es necesario crear unos
stubs
que implementen por un lado el contexto y por el otro la interfaz de
usuario, que es accesible desde la interfaz contexto.
- Examina los stubs que se encuentran en el package test.mx.uam.ingsoft.stub
- En que pruebas se usan instancias de estos stubs?
Paso 4:
Como podrás observar, la realización de pruebas es
automática y se realiza desde ant. Entra al archivo build.xml y
busca el target
test para que
veas como se realiza esto.
Enseguida modifica el archivo build.xml para que el target test quede
como sigue:
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
Ejercicio 3: Clase de pruebas para plugins
Ahora que tienes la versión más actual de la
arquitectura, ve al package de las interfases (comun) y analiza la
interfase Plugin. Como podrás observar, se ha añadido un
nuevo metodo:
getConfigurador().
Este metodo permite a un plugin proveer un objeto que facilita su
configuración en tiempo de ejecución. El configurador es
un objeto que sigue las convenciones getter y setter que vimos en
clase. Si estudias la documentación de la interfase,
verás que el plug-in no debe regresar ningun configurador si aun
no está inicializado.
A hacer:
Basandote en lo que se vio en los dos primeros ejercicios, modifica tu
proyecto de plugins para que incluya un target de prueba de tu plug-in.
Los pasos a seguir son:
- Crear un package de pruebas
- Crear una clase de prueba (puedes dejar que eclipse te
ayude con esto)
- Retormar los stubs del ejercicio anterior y reutilizarlos
- Incluir un target en ant para que se realicen las pruebas y
ponga la salida en formato HTML
- Lanzar las pruebas.