41
Pruebas unitarias JUnit

Introducción a JUnit

Embed Size (px)

DESCRIPTION

Introducción a pruebas unitarias con JUnit.

Citation preview

Page 1: Introducción a JUnit

Pruebas unitariasJUnit

Page 2: Introducción a JUnit

Pruebas unitarias

Conceptos básicos Es una forma de probar el correcto funcionamiento de un módulo de código.

Sirve para asegurar que cada uno de los módulos funcione correctamente por separado.

Con las Pruebas de Integración, se podrá asegurar el correcto funcionamiento del sistema o subsistema en cuestión.

Escribir casos de prueba para cada método en el módulo → cada caso sea independiente del resto.

Page 3: Introducción a JUnit

Pruebas unitarias

Requisitos Automatizable: no debería requerirse una intervención manual. Esto es especialmente útil para integración continua.

Completas: deben cubrir la mayor cantidad de código.

Repetibles o Reutilizables: no se deben crear pruebas que sólo puedan ser ejecutadas una sola vez. También es útil para integración continua.

Page 4: Introducción a JUnit

Pruebas unitarias

Requisitos Independientes: la ejecución de una prueba no debe afectar a la ejecución de otra.

Profesionales: las pruebas deben ser consideradas igual que el código, con la misma profesionalidad, documentación, etc.

Page 5: Introducción a JUnit

Pruebas unitarias

Objetivos Aislar cada parte del programa.

Mostrar que las partes individuales son correctas.

Proporcionan un contrato escrito, que el trozo de código debe satisfacer.

Controlar el impacto de los cambios. Las pruebas unitarias aseguran funcionamiento de código tras cambios del mismo.

Page 6: Introducción a JUnit

Pruebas unitarias

Ventajas Fomentan el cambio: Facilitan al programador cambios de código para mejorar su estructura (refactorización) → Asegura que los nuevos cambios no han introducido errores.

Simplifica la integración: Llegar a fase de integración con seguridad de que el código está OK → Se facilitan las pruebas de integración.

Documenta el código: Las propias pruebas son documentación del código → ahí se puede ver cómo utilizarlo.

Page 7: Introducción a JUnit

Pruebas unitarias

Ventajas Separación de la interfaz y la implementación: La lógica se prueba a través de los casos de prueba y no con interfaz → objetos mock (mock object) para simular el comportamiento de objetos complejos.

Los errores están más acotados y son más fáciles de localizar: Tenemos pruebas unitarias que pueden desenmascararlos.

Page 8: Introducción a JUnit

Pruebas unitarias

Limitaciones Las pruebas unitarias no descubrirán todos los errores del código.

Por definición, sólo prueban las unidades por sí solas → no descubrirán:

• errores de integración• problemas de rendimiento• otros problemas que afectan a todo el sistema en su conjunto

Puede no ser trivial anticipar todos los casos especiales de entradas.

Page 9: Introducción a JUnit

JUnit

Page 10: Introducción a JUnit

JUnit

Conceptos básicos Framework para pruebas unitarias.

Conjunto de librerías creadas por Erich Gamma y Kent Beck que son utilizadas en programación para hacer pruebas unitarias de aplicaciones Java

El framework incluye formas de ver los resultados (runners) que pueden ser en modo texto, gráfico (AWT o Swing) o como tarea en Ant.

Plug-ins para principales IDEs como Eclipse y NetBeans.

Page 11: Introducción a JUnit

JUnit

Conceptos básicos Open Source, disponible en http://www.junit.org

Los casos de prueba son realmente programas Java. Quedan archivados y pueden (DEBEN) ser re-ejecutados tantas veces como sea necesario.

Page 12: Introducción a JUnit

JUnit

Ejemplo sencillopackage dominio;import java.util.Vector;

public class Lista extends Vector {public Lista() { ... }

public Lista(String[] elementos) {...}

public Lista ordenar() {...}

protected void ordenar(int iz, int de) {...

} }

← Representa una lista ordenable de forma creciente.

Se ordena llamando al método público ordenar(), que llama a su vez a ordenar(0, size()-1)

Page 13: Introducción a JUnit

JUnit

Ejemplo sencillo•Un posible caso de prueba es el siguiente:String[] e3={"e", "d", "c", "b", "a"};Lista reves=new Lista(e3);Lista derecha=reves.ordenar();

...y el resultado esperado:

"a", "b", "c", "d", "e"

Page 14: Introducción a JUnit

JUnit

Ejemplo sencilloString[] e3={"e", "d", "c", "b", "a"};Lista reves=new Lista(e3);Lista derecha=reves.ordenar();

Si derecha es igual al resultado esperado, entonces el caso de prueba ha sido superado

{"a", "b", "c", "d", "e"}

Page 15: Introducción a JUnit

JUnit

Ejemplo sencillo Construcción manual de un objeto expected y comparación con el obtenido:

String[] e3={"e", "d", "c", "b", "a"};Lista reves=new Lista(e3);Lista derecha=reves.ordenar();Lista expected={"a", "b", "c", "d", "e"};if (derecha.equals(expected)) ResultadoCorrecto();

elseResultadoIncorrecto();

Page 16: Introducción a JUnit

JUnit

Ejemplo sencillo El ejemplo anterior (obtained frente a expected) es una idea fundamental de JUnit

¿ Qué nos ofrece JUnit?• JUnit permite mantener de forma separada los casos de prueba• Permite ejecutarlos (y re-ejecutarlos) de forma automática• Nos permite construir "árboles de casos de prueba" (suites)

Page 17: Introducción a JUnit

JUnit

Ejemplo sencillo El ejemplo anterior con JUnit:public void testOrdenarReves() {

String[] ex={"a", "b", "c", "d", "e"};Lista expected=new Lista(ex);

String[] e3={"e", "d", "c", "b", "a"};listaAlReves=new Lista(e3);

this.assertEquals(expected, listaAlReves.ordenar());}

Page 18: Introducción a JUnit

JUnit

Ejemplo sencillo ¿Dónde está el código anterior? En la clase ListaTester, creada para realizar las pruebas de Lista.

ListaTester extiende de TestCase definida en Junit.

En TestCase está definido el método assertEquals antes mencionado, y muchos otros más.

Page 19: Introducción a JUnit

JUnit

Ejemplo sencillopublic class ListaTester1 extends TestCase{

public ListaTester1(String sTestName){

super(sTestName);}

public void testOrdenarReves() {String[] ex={"a", "b", "c", "d", "e"};Lista expected=new Lista(ex);

String[] e3={"e", "d", "c", "b", "a"};Lista listaAlReves=new Lista(e3);

this.assertEquals(expected, listaAlReves.ordenar());}

}

Page 20: Introducción a JUnit

JUnit

El TestRunnerpublic class ListaTester1 extends TestCase{public ListaTester1(String sTestName){

super(sTestName);}

public void testOrdenarReves() {String[] ex={"a", "b", "c", "d", "e"};Lista expected=new Lista(ex);

String[] e3={"e", "d", "c", "b", "a"};Lista listaAlReves=new Lista(e3);

this.assertEquals(expected, listaAlReves.ordenar());

}

}

Page 21: Introducción a JUnit

JUnit

El TestRunnerpublic void testOrdenarReves() {

String[] ex={"a", "b", "c", "d", "e"};Lista expected=new Lista(ex);

String[] e3={"e", "d", "c", "b", "a"};Lista listaAlReves=new Lista(e3);

this.assertEquals(expected,listaAlReves.ordenar());

}

public void testOrdenarTodosIguales() {String[] e2={"a", "a", "a", "a", "a"};Lista listaTodosIguales=new Lista(e2);

String[] ex={"a", "a", "a", "a", "a"};Lista expected=new Lista(ex);this.assertEquals(expected,listaTodosIguales.ordenar());

}

public void testOrdenarNula1() {Lista listaNula1=null;this.assertNull(listaNula1);

}

public void testOrdenarNula2() {String[] e4=null;Lista listaNula2=new Lista(e4);String[] ex=null;Lista expected=new Lista(ex);this.assertEquals(expected,listaNula2.ordenar());

}

public void testOrdenarListaVacia() {String[] e5={};Lista listaVacia=new Lista(e5);String[] ex={};Lista expected=new Lista(ex);this.assertEquals(expected,listaVacia.ordenar());

}

Page 22: Introducción a JUnit

JUnit

El TestRunner – Errors vs Failures

Page 23: Introducción a JUnit

JUnit

El TestRunner – Test OK

Page 24: Introducción a JUnit

JUnit

TestRunner - Consideraciones Es importante notar que todos los métodos test que implementados se están en ListaTester.

Si añadimos, borramos o modificamos el código de Lista, los casos de prueba habidos en ListaTester siguen disponibles y pueden volver a ser ejecutados.

Se aconseja/OBLIGA re-ejecutarlos cada vez que se modifique el código.

Page 25: Introducción a JUnit

JUnit

Pruebas de Excepciones (fail) Es necesario comprobar el comportamiento en situaciones idóneas, pero se deben probar situaciones en las que se producen errores.

A veces el comportamiento correcto de nuestro programa consisten en se produzca un error una →excepción.

Page 26: Introducción a JUnit

JUnit

Pruebas de Excepciones (fail) Por ejemplo, puede ser deseable que ordenar() lance un error cuando la lista esté vacía:

public Lista ordenar() throws Exception {if (size()==0)

throw new Exception("No se puede ordenar una lista vacía");ordenar(0, size()-1);return this;

}

Page 27: Introducción a JUnit

JUnit

Pruebas de Excepciones (fail)public void testOrdenarNula2()

throws Exception {String[] ex=null;Lista expected=new Lista(ex);this.assertEquals(expected,

listaNula2.ordenar());}

public void testOrdenarListaVacia() throws Exception {

String[] ex={};Lista expected=new Lista(ex);this.assertEquals(expected,

listaVacia.ordenar());}

Page 28: Introducción a JUnit

JUnit

Pruebas de Excepciones (fail) Se modificarán los métodos test de la siguiente manera:

public void testOrdenarNula2() throws Exception {try{

String[] ex=null;Lista expected=new Lista(ex);this.assertEquals(expected, listaNula2.ordenar());fail("Debería haberse lanzado una excepción");

}catch (Exception e){

// Capturamos la excepción para que el caso no falle}

}

Page 29: Introducción a JUnit

JUnit

Redefinición de método equals Todas las clases Java extienden de Object y por lo tanto heredan: Llamado por los

assertEquals(...)definidos en Assert

Page 30: Introducción a JUnit

JUnit

Redefinición de método equals Por tanto, en muchos casos habrá que redefinir el método equals(Object):boolean en la clase que se quiera probar.

Page 31: Introducción a JUnit

JUnit

Ejemplo - equals

¿Cuándo son dos cuentas son iguales?a) Los saldos son los mismosb) Tienen el mismo nº de

movimientosc) Opción b y todos son igualesd) ...

Page 32: Introducción a JUnit

JUnit

Ejemplo - equalspublic void testIngresarYRetirarloTodo() throws Exception{Cuenta expected=new Cuenta("Pepe", "123");

Cuenta obtained=new Cuenta("Macario", "123456");obtained.ingresar(1000.0);obtained.retirar(1000.0);

assertEquals(expected, obtained);}

Page 33: Introducción a JUnit

JUnit

Ejemplo - equals

public boolean equals(Object o){if (!Cuenta.class.isInstance(o))

return false;Cuenta c=(Cuenta) o;return getSaldo()==c.getSaldo());

}

public void testIngresarYRetirarloTodo() throws Exception{

Cuenta expected=new Cuenta("Pepe", "123");

Cuenta obtained=new Cuenta("Macario", "123456");obtained.ingresar(1000.0);obtained.retirar(1000.0);

assertEquals(expected, obtained);}

Si redefinimos equals(Object): boolean en Cuenta de ese modo...

Page 34: Introducción a JUnit

JUnit

Otros métodos assert assertTrue(boolean)

assertNull(Object)

public void testIngresar(){

Cuenta obtained=new Cuenta("Pepe", "123");obtained.ingresar(100.0); obtained.ingresar(200.0);obtained.ingresar(300.0);assertTrue(obtained.getSaldo()==600.0);

}

public void testNull() {

Cuenta c=null;assertNull(c);

}

Page 35: Introducción a JUnit

JUnit

Otros métodos assert assertSame(Object, Object)/assertNotSame(Object, Object)

public void testDiferentesReferencias() throws Exception{

Cuenta cuenta1=new Cuenta("Macario", "123456");cuenta1.ingresar(1000.0);cuenta1.retirar(1000.0);

Cuenta cuenta2=new Cuenta("Macario", "123456");cuenta2.ingresar(1000.0);cuenta2.retirar(1000.0);

assertEquals(cuenta1, cuenta2);assertNotSame(cuenta1, cuenta2);

}

Page 36: Introducción a JUnit

JUnit

Mock Objects Basados en JUnit.

Sustituyen a clases complejas, dispositivos, etc.

Ejemplos: servlets, páginas jsp, bases de datos...

Page 37: Introducción a JUnit

JUnit

Mock Objects - Ejemplopublic class temperature extends HttpServlet {private static final String CONTENT_TYPE = "text/html";

public void init(ServletConfig config) throws ServletException {super.init(config);

}

public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException

{response.setContentType(CONTENT_TYPE);PrintWriter out = response.getWriter();String str_f=request.getParameter("Fahrenheit");

try {int temp_f=Integer.parseInt(str_f);double temp_c=(temp_f-32)*5/9.0;out.println("Fahrenheit: " + temp_f + ", Celsius: " + temp_c);

}catch (NumberFormatException e) {out.println("Invalid temperature: " + str_f);

}}

}

Page 38: Introducción a JUnit

JUnit

Mock Objects - Ejemploimport com.mockobjects.servlet.*;import junit.framework.Test;import junit.framework.TestCase;import junit.framework.TestSuite;

public class TemperatureTester extends TestCase{public TemperatureTester(){}

public void test_bad_parameter() throws Exception {temperature s = new temperature();MockHttpServletRequest request=new MockHttpServletRequest();MockHttpServletResponse response=new MockHttpServletResponse();request.setupAddParameter("Fahrenheit", "boo!");response.setExpectedContentType("text/html");s.doGet(request, response);response.verify();assertTrue(response.getOutputStreamContents().startsWith("Invalid temperature"));

}

Page 39: Introducción a JUnit

JUnit

Mock Objects Difíciles de usar (poca documentación)

Descargas y más información en www.mockobjects.com

Page 40: Introducción a JUnit

JUnit

Conclusiones Marco de automatización de pruebas.

Automatiza las pruebas de regresión.

Los casos de prueba documentan el propio código fuente.

Adecuado para Desarrollo dirigido por las pruebas.

Extensible (p.ej.: Mock), abierto, gratuito :)

Page 41: Introducción a JUnit

FINPruebas Unitarias - JUnit

Iker [email protected]