Download Indice Introducción

Document related concepts
no text concepts found
Transcript
EPS, Informática
EPS, Informática
Indice
JUnit
„
„
„
„
Guía básica de uso
„
„
http://www.junit.org
„
Introducción
Descripción
Creación de una clase de prueba para una
clase Java.
Ejecución de los casos de prueba
Manejo de excepciones con JUnit
Prueba de los métodos privados
Extensiones de JUnit
Daniel Bolaños - [email protected]
EPS, Informática
Introducción
„ Se
trata de un conjunto de clases que
nos permiten realizar pruebas unitarias
sobre código Java.
„ Está desarrollado en Java.
„ JUnit es Software de código abierto y
está alojado en SourceForge.
„ Página principal: www.junit.org.
EPS, Informática
Descripción
JUnit consta de varios paquetes (packages) de clases
„ Paquetes para construir los casos de prueba
– junit.framework, contiene las clases básicas de junit que
utilizaremos para construir los casos de prueba.
– junit.extensions, contiene clases que extienden la
funcionalidad de las clases básicas.
„
Paquetes para ejecutar los casos de prueba
– junit.textui, permite ejecutar los casos de prueba en una
interfaz de texto.
– junit,awtui, proporciona una interfaz gráfica AWT para la
ejecución de los casos de prueba.
– junit.swingui, proporciona una interfaz gráfica Swing para la
ejecución de los casos de prueba.
EPS, Informática
EPS, Informática
Paquete junit.framework
Paquete junit.framework, clase Assert
Nos proporciona un conjunto de clases para construir nuestros
casos de prueba, las más importantes son:
„
„
//Condiciones de igualdad
static void assertEquals(boolean expected, boolean actual)
static void assertEquals(float expected, float actual, float delta)
„
Assert, proporciona una serie de métodos estáticos para
comprobar el cumplimiento de condiciones sobre el código a
probar.
„ TestCase, representa un conjunto de pruebas sobre una clase,
permite realizar múltiples pruebas sobre sus métodos.
„ TestSuite, permite agrupar diferentes objetos TestCase para su
ejecución conjunta.
„ TestResult, permite almacenar los resultados de la ejecución
de uno o varios TestCase, de esta forma conoceremos los
resultados de las pruebas.
Todos sus métodos son estáticos.
Posee métodos para probar todo tipo de condiciones.
//Condiciones booleanas
static void assertTrue(boolean condition)
static void assertFalse(boolean condition)
//Condiciones sobre objetos
static void assertNull(java.lang.Object object)
static void assertNotNull(java.lang.Object object)
//Condiciones sobre referenacias a objetos
static void assertSame(java.lang.Object expected, java.lang.Object actual)
static void assertNotSame(java.lang.Object expected, java.lang.Object actual)
„
Contiene un método fail para indicar de forma explícita que el test ha
fallado.
static void fail(java.lang.String message)
EPS, Informática
EPS, Informática
Paquete junit.framework, clase TestCase
Paquete junit.framework, clase TestSuite
„
„
„
„
„
„
Representa el conjunto de pruebas que se van a realizar sobre
los métodos de una clase.
Hereda de Assert, por lo que posee todos sus métodos para la
comprobación de condiciones.
Implementa la interfaz Test.
La forma de utilizar esta clase es heredando de ella para
construir nuestras clases de prueba.
Sus métodos más importantes son:
//Ejecuta los métodos de test (todos los que comienzan por “test”)
void run(TestResult result)
//Realiza todas las inicializaciones necesarias para la prueba
protected void setUp()
//Libera todos los recursos utilizados durante la prueba
protected void tearDown()
Representa una conjunto de casos de prueba.
„ Implementa la interfaz Test, por tanto implementa el método run
para la ejecución de los tests.
void run(TestResult result)
„
Existen varias formas de utilizarlo:
//Creamos un TestSuite y añadimos varios métodos de prueba para ser ejecutados
TestSuite suite= new TestSuite();
suite.addTest(new MathTest("testAdd"));
suite.addTest(new MathTest("testDivideByZero"));
//Creamos un TestSuite a partir de los métodos de test de una clase, es decir
//aquellos que comienzan por “test” y no tienen argumentos, simplemente
//pasamos la clase y todos los métodos de test se extraen automáticamente para
//formar parte del TestSuite
TestSuite suite= new TestSuite(MathTest.class);
EPS, Informática
Creación de una clase de prueba para una clase
Java
EPS, Informática
Ejemplo: prueba de la clase java.util.Vector
package junit.samples;
Para realizar la prueba de una clase Java con JUnit debemos dar los
siguientes pasos
1.
2.
3.
4.
import junit.framework.*;
import java.util.Vector;
Creamos una clase que herede de TestCase, esta clase se encargará de
realizar las pruebas sobre nuestra clase a probar, y seguirá la
nomenclatura NombreClaseProbarTest.
Sobrescribimos el método setUp para hacer las inicializaciones
necesarias para la prueba, es decir, conexiones de red, apertura de
ficheros, instanciación de clases, etc.
Sobreescribimos el método tearDown, que se encargará de liberar todos
los recursos utilizados durante la prueba.
Para cada método público de la clase a probar definiremos un método
de test, que seguirá la nomenclatura testMetodoProbar. Este método
debe realizar todas las pruebas necesarias sobre el método a probar, lo
invocará de diferentes formas y comprobará condiciones sobre su
retorno mediante el uso de asserts, heredados por TestCase de su clase
padre Assert.
public class VectorTest extends TestCase {
protected Vector fEmpty;
protected Vector fFull;
public static void main (String[] args) {
junit.textui.TestRunner.run (suite());
}
protected void setUp() {
fEmpty= new Vector();
fFull= new Vector();
fFull.addElement(new Integer(1));
fFull.addElement(new Integer(2));
fFull.addElement(new Integer(3));
}
EPS, Informática
Ejemplo: prueba de la clase java.util.Vector
EPS, Informática
Ejemplo: prueba de la clase java.util.Vector
public void testElementAt() {
Integer i= (Integer)fFull.elementAt(0);
assertTrue(i.intValue() == 1);
public static Test suite() {
return new TestSuite(VectorTest.class);
}
public void testCapacity() {
int size= fFull.size();
for (int i= 0; i < 100; i++)
fFull.addElement(new Integer(i));
assertTrue(fFull.size() == 100+size);
}
public void testClone() {
Vector clone= (Vector)fFull.clone();
assertTrue(clone.size() == fFull.size());
assertTrue(clone.contains(new Integer(1)));
}
public void testContains() {
assertTrue(fFull.contains(new Integer(1)));
assertTrue(!fEmpty.contains(new Integer(1)));
}
try {
fFull.elementAt(fFull.size());
} catch (ArrayIndexOutOfBoundsException e) {
return;
}
fail("Should raise an ArrayIndexOutOfBoundsException");
}
public void testRemoveAll() {
fFull.removeAllElements();
fEmpty.removeAllElements();
assertTrue(fFull.isEmpty());
assertTrue(fEmpty.isEmpty());
}
public void testRemoveElement() {
fFull.removeElement(new Integer(3));
assertTrue(!fFull.contains(new Integer(3)) );
}
}
EPS, Informática
EPS, Informática
Ejecución de los casos de prueba
Ejecución de los casos de prueba
„
Ejemplo: vamos a probar las clases Vector, String y StringBuffer, mediante
sus correspondientes clases de prueba.
A la hora de ejecutar nuestros casos de prueba podemos
utilizar una de estas tres clases
– JUnit.textui.TestRunner, esta clase permite ejecutar las clases de
prueba a través del método run.
//Inicialmente creamos el obeto TestSuite y le añadimos los test de
//las diferentes clases de prueba
TestSuite testSuite = new TestSuite(VectorTest.class);
testSuite.addTestSuite(StringTest.class);
testSuite.addTestSuite(StringBufferTest.class);
static TestResult run (Test test);
Este método recibe como argumento un objeto que implemente la
interfaz Test (TestCase y TestSuite la implementan) y devuelve un
objeto de tipo TestResult con la información que se ha obtenido
como resultado de la ejecución de los métodos de prueba
contenidos en dicho objeto.
– JUnit.awtui.TestRunner, esta clase es equivalente a la anterior,
sólo que presenta una interfaz AWT.
– JUnit.swingtui.TestRunner, esta clase es equivalente a la anterior,
sólo que presenta una interfaz Swing.
//Ejecutamos los test y almacenamos el resultado
TestResult testResult = junit.textui.TestRunner.run(testSuite);
Una vez finalizada la ejecución de las pruebas podemos utilizar la
información contenida en el testResult para generar documentación de
forma automática.
EPS, Informática
Manejo de excepciones con JUnit
„
Excepciones esperadas: veámoslo con un ejemplo
public void testMetodoQueLanzaExcepcion() {
try {
//Invocamos el método de forma que deba lanzar una excepción
metodoQueLanzaExcepcion(null);
//Si el flujo de control pasa por aquí es porque la excepción
//no saltó, entonces indicamos que ha habido un fallo
fail(“El método debería haber lanzado una excepción”);
EPS, Informática
Manejo de excepciones con JUnit
„
Otra forma de manejar las excepciones esperadas es haciendo
uso de la clase ExceptionTestCase, perteneciente al paquete
junit.extensions. Esta clase hereda de TestCase y espera que
una excepción de un tipo dado sea lanzada, veamos un
ejemplo:
//Heredamos de ExceptionTestCase en lugar de TestCase
public class MiClaseTest() extends ExceptionTestCase {
} catch (RunTimeException e) {
//A modo de documentación, para indicar que la prueba ha
//tenido éxito el flujo de control ha de pasar por aquí
assertTrue(true);
}
public MiClaseTest(String name, Class exception) {
super(name,exception);
}
//Debemos llamar al constructor de la superclase con la clase de
//la excepción que puede lanzar el método a probar
MiClaseTest new MiClaseTest(“nombre", ExcepcionLanzada.class);
EPS, Informática
Manejo de excepciones con JUnit
EPS, Informática
Manejo de excepciones con JUnit
public class ExceptionTestCase extends TestCase {
„
Class fExpected;
public ExceptionTestCase(String name, Class exception) {
super(name);
fExpected= exception;
}
protected void runTest() throws Throwable {
try {
super.runTest();
}
catch (Exception e) {
if (fExpected.isAssignableFrom(e.getClass()))
return;
else
throw e;
}
fail("Expected exception " + fExpected);
}
Excepciones no esperadas: en este caso no tenemos que
preocuparnos de capturar las excepciones, simplemente
declararemos nuestro método de prueba de forma que pueda
lanzar todas aquellas excepciones que pueda lanzar el método
a probar. Veámoslo con un ejemplo.
public void testMetodoQueLanzaExcepcion() throws
FileNotFoundException {
//Invocamos el método de forma que no deba fallar
FileInputStream entrada = new FileInputStream(“datos.txt”);
}
}
EPS, Informática
EPS, Informática
Prueba de los métodos privados
Prueba de los métodos privados
„
„
Primer enfoque: no probarlos directamente, sino a través de los
métodos públicos que los utilizan. El problema es que esto no
es tan sencillo ya que garantizar una cobertura en la prueba de
un método a través de la cobertura en la prueba de otro que le
llama, puede resultar bastante complejo.
„ Cambiar el atributo de privacidad del método “private” por el de
acceso desde el mismo paquete, es decir, sin atributo. Estás
sacrificando la modularidad y la ocultación de datos en favor de
la calidad de las pruebas.
„ Utilizar clases anidadas, se trata de una solución parecida a la
anterior, el problema es que mezclamos el código de la clase a
probar con el código de la prueba, y esto conlleva problemas en
el mantenimiento.
Utilizar reflection, mediante la API java.lang.reflect es posible
saltarse el mecanismo de protección de acceso de la máquina
virtual de Java, mediante la clase junitx.util.PrivateAccessor
podemos manipular los métodos privados de cualquier clase.
Ventajas
„ Separación limpia entre el código
de test y el código de producción.
„ No es necesario anidar la clase de
test dentro de la clase a testear.
„ No es necesario modificar la API
de la clase a testear.
Inconvenientes
„ Es necesario utilizar la API de
reflection dentro de nuestras
clases de prueba.
„ Puesto que al utilizar
reflection, te refieres a los
métodos como Strings, si
cambiamos el nombre del
método, hay que cambiar el
código de la prueba.
EPS, Informática
Extensiones de JUnit
JTestCase
„
Debido a la gran difusión de JUnit, existen multitud de paquetes
que extienden su funcionalidad, entre otras cosas permiten:
„
Generación automática de documentación sobre los resultados de la
prueba (JUnitReport).
Generación automática de los casos de prueba a partir del código
fuente.
Tests sobre los tests.
Separación de los datos y el código en los casos de prueba mediante
documentos XML (JTestCase).
Pruebas concurrentes.
Prueba de excepciones (paquete junit.extensions).
Pruebas distribuidas utilizando HTTP (JHttpUnit).
Pruebas de sitios WEB (JWebUnit).
Pruebas de interfaces de usuario (JFCUnit para Swing)
...
„
„
„
„
„
„
„
„
„
EPS, Informática
„
Es un framework de código abierto, reside en
SourceForge, http://jtestcase.sourceforge.net/
„
Permite almacenar en ficheros XML los datos con los
que se ejecutarán los casos de prueba, de esta
forma conseguimos:
– Posibilidad de ampliar el conjunto de datos de entrada a los
tests sin modificar el código de las pruebas.
– La persona que diseña los conjuntos de datos de entrada no
tiene porque saber como está hecho el código de las
pruebas.
EPS, Informática
EPS, Informática
JTestCase
JTestCase
„
„
Ejemplo: deseamos probar la clase Calculator
Un fichero xml contiene información acerca de los parámetros con los que se
han de probar nuestras clases y métodos.
package sample;
public class Calculator {
public int calculate(int v1, int v2, String opt) throws Exception {
if (opt.equals("+"))
return v1 + v2;
else if (opt.equals("-"))
return v1 - v2;
else if (opt.equals("*"))
return v1 * v2;
else if (opt.equals("/"))
return (int)(v1/v2);
else
throw new Exception("Unknown operator " + opt + "!");
}
public String func2() throws Exception {
return "Who cares!";
}
}
<?xml version="1.0" encoding="UTF-8" ?> <tests xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:noNamespaceSchemaLocation="config/jtestcase.xsd"><class name="CalculatorTest"><!-- global params --> <params>
<param name="hashInit" type="java.util.Hashtable" />
</params>
<method name="testCalculate" test-case="positive-add">
<params>
<param name="var1" type="int">10</param>
<param name="var2" type="int">20</param>
<param name="opt" type="java.lang.String">+</param>
</params><asserts>
<assert name="result" type="int“ action="EQUALS">30</assert>
</asserts>
</method>-
EPS, Informática
JTestCase
<method name="testCalculate" test-case="positive-minus">
<params>
<param name="var1" type="int">10</param>
<param name="var2" type="int">20</param>
<param name="opt" type="java.lang.String">-</param>
</params><asserts>
<assert name="result" type="int" action="EQUALS">-10</assert>
</asserts>
</method><method name="testCalculate" test-case="negative-wrong-opt"><params>
<param name="var1" type="int">10</param>
<param name="var2" type="int">20</param>
<param name="opt" type="java.lang.String">ccxx</param>
</params><asserts>
<assert name="" type="java.lang.String" action="EQUALS">N/A: should throw
Exception</assert>
</asserts>
</method><method name="testFunc2" test-case="positive">
<params />
<asserts />
</method>
</class>
</tests>