Comunidad de diseño web y desarrollo en internet online

Unit testing, JUnit y TDD para Java

Citar            
MensajeEscrito el 18 Abr 2012 06:00 pm

¿Qué es JUnit?


JUnit es un conjunto de bibliotecas creadas por Erich Gamma y Kent Beck que son utilizadas en programación para hacer pruebas unitarias de aplicaciones Java. JUnit es un conjunto de clases (framework) que permite realizar la ejecución de clases Java de manera controlada, para poder evaluar si el funcionamiento de cada uno de los métodos de la clase se comporta como se espera.

¿Cómo funciona JUnit?


Basicamente, en funci ́n de alg ́n valor de entrada se evalúa el valor de retorno esperado; si la clase cumple con la especificación, entonces JUnit devolverá que el método de la clase pasó exitosamente la prueba; en caso de que el valor esperado sea diferente al que retornó el método durante la ejecución, JUnit devolverá un fallo en el método correspondiente.

¿Qué es TDD?


Desarrollo guiado por pruebas, o Test-driven development(TDD) es una práctica de programación que involucra otras dos prácticas: Escribir las pruebas primero (Test First Development) y Refactorización (Refactoring).

¿Cómo funciona TDD?


En Primer Lugar se escribe una prueba y se verifica que las pruebas fallen, luego se implementa el código que haga que la prueba pase satisfactoriamente y seguidamente se hace un refactor del código escrito.

Ciclo de desarrollo


TDD se basa en un desarrollo iterativo e incremental, para el cual se recomienda seguir los siguientes pasos:
  1. Elegir un requisito: Se elige de una lista el requerimiento que se cree que nos dará mayor
    conocimiento del problema y que a la vez sea fácilmente implementable.

  2. Escribir una prueba: Se comienza escribiendo una prueba para el requisito. Para ello el programador debe entender claramente las especificaciones y los requisitos de la funcionalidad que está por implementar. Este paso fuerza al programador a tomar la perspectiva de un cliente considerando el código a través de sus interfaces.

  3. Verificar que la prueba falla: Si la prueba no falla es porque el requerimiento ya estaba implementado o porque la prueba es errónea.

  4. Escribir la implementación: Escribir el código más sencillo que haga que la prueba funcione.

  5. Ejecutar las pruebas automatizadas: Verificar si todo el conjunto de pruebas funciona correctamente.

  6. Eliminación de duplicación: El paso final es la refactorización, que se utilizará principalmente para
    eliminar código duplicado. Se hacen de a una vez un pequeño cambio y luego se corren las pruebas hasta que funcionen.

  7. Actualización de la lista de requisitos: Se actualiza la lista de requisitos tachando el requisito implementado. Asimismo se agregan requisitos que se hayan visto como necesarios durante este ciclo.


Ventajas



  1. Los programadores que usan TDD para un proyecto desde cero son raras las veces que necesitan usar un debbuger.

  2. Ayuda a producir aplicaciones de más calidad y en menos tiempo.

  3. Además de validar el cumplimiento de los requisitos, también puede guiar el diseño de un programa.

  4. Cuando es bien utilizado, nos asegura que todo el código está cubierto por una prueba.


Limitaciones


El desarrollo guiado por pruebas requiere que las pruebas puedan automatizarse. Esto resulta complejo en los siguientes dominios:

  1. Interfaces Gráfica de usuario (GUIs).

  2. Objetos distribuidos, aunque los objetos simulados(MockObjects) pueden ayudar.

  3. Bases de datos. Hacer pruebas de código que trabaja con base de datos es complejo porque requiere poner en la base de datos unos datos conocidos antes de hacer las pruebas. Todo esto hace que la prueba sea costosa de codificar.


JUnit y NetBeans


NetBeans integra la librería JUnit de forma que es muy sencillo crear un test para una clase determinada. Esta librería aparece con el nombre JUnit como uno de los plugins disponibles para descargar.
A continuación vamos a ver en base a un ejemplo como utilizar JUnit con las facilidades que nos proporciona NetBeans.

Ejemplo


Problema: determinar si un año es bisiesto.

¿Cuando un año es bisiesto?

  • Un año es bisiesto si es divisible por cuatro lo que provoca que uno de cada cuatro años sea bisiesto.

  • Para un mayor ajuste los años divisibles por 100 no serán bisiestos, de tal forma que cada 100 años habrá un año que debería ser bisiesto y no lo es.

  • Sin embargo si el año es divisible por 400 sí que es bisiesto, así cada 400 años habrá un año que no debería ser bisiesto pero sí que lo es.


Si bien TDD dice que lo primero es crear clases de test, se puede aprovechar las ventajas de NetBeans. Para ello se crea la clase con el método isLeap que retorna false para que siempre falle, y en base a esta clase se genera la clase de test.
Para ello, como muestra la imágen, al hacer click con el botón derecho podremos crear la clase para test:


La opción anterior nos mostrará la siguiente ventana:


Y el código generado es el siguiente:

Código Java :

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

public class YearUtilitiesTest {
    public YearUtilitiesTest() {
    }

    @BeforeClass
    public static void setUpClass() throws Exception {
    }
    
    @AfterClass
    public static void tearDownClass() throws Exception {
    }

    @Before
    public void setUp() {
    }

    @After
    public void tearDown() {
    }

    public void testIsLeap() {
        System.out.println("isLeap");
        int year = 0;
        YearUtilities instance = new YearUtilities();
        boolean expResult = false;
        boolean result = instance.isLeap(year);
        assertEquals(expResult, result);
        fail("The test case is a prototype.");
    }
}


Ahora bien, ¿Qué son todos esos métodos generados?
JUnit da la facilidad de poder ejecutar cosas antes y después de que se ejecute cada test, o inclusive antes y después de todos los test.

  • setUpClass(): Ejecuta lo que el desarrollador desee antes de ejecutar la clase de test
  • tearDownClass(): Ejecuta lo que el desarrollador desee después de ejecutar la clase de test
  • setUp(): Se ejecuta antes de ejecutar cada uno de los test
  • tearDown(): Se ejecuta después de ejecutar cada uno de los test


Estos métodos son útiles para cuando necesitamos inicializar cosas, como bases de datos, borrar archivos resultantes, etc. Si no se necesitase alguno de estos métodos, simplemente se los puede quitar.

Ahora modificamos el código tratando de poner años que cubran todas las opciones. Por otro lado, borramos los métodos setUpClass(), tearDownClass(), setUp() y tearDown() ya que en este caso no necesitamos hacer nada ni antes ni después de la ejecución de los test. Entonces, así nos quedaría el código:

Código Java :

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

public class YearUtilitiesTest {

    public void testIsLeap() {
        YearUtilities instance = new YearUtilities();
        assertTrue(instance.isLeap(4));//es bisiesto
        assertFalse(instance.isLeap(100));//no es bisiesto
        assertTrue(instance.isLeap(400));//es bisiesto
        assertFalse(instance.isLeap(2011));//no es bisiesto
        assertTrue(instance.isLeap(2012));//es bisiesto
    }
}

E implementamos el método isLeap:

Código Java :

public class YearUtilities {
    public boolean isLeap(int year){
        if(year%4 == 0){
            if(year%100 == 0){
                if(year%400 == 0){
                    return true;
                }else{
                    return false;
                }
            }else{
                return true;
            }
        }else{
            return false;
        }
    }
}

Ejecutamos el test desde el menú Run->Test Project


Como muestra la figura, nos marca en verde y nos dice que el 100 % de los test fueron superados.

Ahora bien, modifiquemos el método isLeap para que una de las pruebas arroje un error:

Código Java :

public class YearUtilities {
    public boolean isLeap(int year){
        if(year%4 == 0){
            if(year%100 == 0){
                if(year%400 == 0){
                    return false; //cambiamos true por false
                }else{
                    return false;
                }
            }else{
                return true;
            }
        }else{
            return false;
        }
    }
}

Ejecutamos nuevamente el test:


Como se puede observar, nos dice que uno de los tests falló y desplegando el error mostrará la linea del fallo.

Aserciones de JUnit


Como se pudo observar en el ejemplo, se utilizaron los métodos assertTrue y assertFalse para evaluar si el valor retornado por el método es el esperado.
A continuación se presenta una tabla describiendo las aserciones de JUnit:

  • assertEquals: Evalúa si dos objetos pasados por parámetro son iguales.
  • assertFalse: Evalúa si la condición pasada es false.
  • assertNotNull: Comprueba que la condición no sea nula.
  • assertNotSame: Comprueba que dos objetos no sean la misma instancia.
  • assertNull: Comprueba si un objeto es nulo.
  • assertSame: Opuesto a assertNotSame.
  • assertTrue: Opuesto a assertFalse.
  • fail: Útil para detectar si estamos en un sitio del programa donde no deberíamos estar.

Un ejemplo de utilización del método fail es el siguiente:

Código Java :

protected void runTest(){
    try{
        File fichero = new File(nombreFichero);
        assertTrue("Podemos Leer",fichero.canRead());
    }catch(Exception e){
        fail("Fallo al identificar Fichero " + nombreFichero);
    }
}

En caso de no poder leer el archivo, lanzará una excepción y el método fail escribirá el error.

Bibliografía:


Por alvarogili

11 de clabLevel



Genero:Masculino  



Ultima edición por alvarogili el 19 Abr 2012 05:30 pm, editado 1 vez

Desarrollo de software

firefox
Citar            
MensajeEscrito el 19 Abr 2012 01:49 am
Hola alvarogili, tu tutorial es un copy paste de wikipedia y de este apunte. No pasamos a portada tutoriales que nos enteramos que son pirateados. El contenido publicado en cristalab es 100% hecho por los usuarios.

Sí se permiten algunas traducciones o explicaciones de códigos hechos por otros, pero siempre se referencia el artículo y autor, cosa que vos no hiciste en este tuto.

Podés volver a intentarlo, pero tené en cuenta que acá hay muchísima gente que puede descubrirte el plagio en el caso de que yo me lo pase por alto.

Por Mariux

BOFH

7756 de clabLevel

28 tutoriales
15 articulos

Genero:Femenino   Héroes Editores

Diseñadora & ilustradora

chrome
Citar            
MensajeEscrito el 19 Abr 2012 01:57 am
hola mariux, mi tuto se basa en ese articulo y en algunos otros más, como la wikipedis, es una presentación que día en mi empresa, pero la verdad es que no supe como poner las referencias, te agradecería sí me das una mano con eso

Por alvarogili

11 de clabLevel



Genero:Masculino  

Desarrollo de software

firefox
Citar            
MensajeEscrito el 19 Abr 2012 02:21 am

alvarogili escribió:

hola mariux, mi tuto se basa en ese articulo y en algunos otros más, como la wikipedis, es una presentación que día en mi empresa, pero la verdad es que no supe como poner las referencias, te agradecería sí me das una mano con eso


No, hacer un artículo con bases en otros (lo que es aceptable) implica hacer una producción propia del texto, con una aplicacion práctica original, pensado por uno y aplicándole los conocimientos que uno adquirió al leer esos textos.

Vos solamente copiaste y pegaste textos de la web, sin ningun cambio ni resumen. Ni siquiera pensaste en cambiar el ejemplo!!!! Hiciste un hermoso bricollage de diferentes artículos, que quedó muy bien, pero no ayuda a nadie.

La web no sirve para esto, realmente estas usando mal internet y todo el contenido que tiene para que uno aprenda.

Por Mariux

BOFH

7756 de clabLevel

28 tutoriales
15 articulos

Genero:Femenino   Héroes Editores

Diseñadora & ilustradora

chrome
Citar            
MensajeEscrito el 19 Abr 2012 11:09 am

Mariux escribió:

alvarogili escribió:

hola mariux, mi tuto se basa en ese articulo y en algunos otros más, como la wikipedis, es una presentación que día en mi empresa, pero la verdad es que no supe como poner las referencias, te agradecería sí me das una mano con eso


No, hacer un artículo con bases en otros (lo que es aceptable) implica hacer una producción propia del texto, con una aplicacion práctica original, pensado por uno y aplicándole los conocimientos que uno adquirió al leer esos textos.

Vos solamente copiaste y pegaste textos de la web, sin ningun cambio ni resumen. Ni siquiera pensaste en cambiar el ejemplo!!!! Hiciste un hermoso bricollage de diferentes artículos, que quedó muy bien, pero no ayuda a nadie.

La web no sirve para esto, realmente estas usando mal internet y todo el contenido que tiene para que uno aprenda.


Hola de nuevo, te voy a pedir más respeto hacia mi, ya que no me conoces, este bricollage como lo llamas vos, proviene de unas diapositivas que realicé hace ya bastante tiempo para darle una introducción a Junit 3 a gran parte del área de desarrollo de mi empresa, y justamente, este viernes me toca capacitar al resto, entonces, al estar acomodandolas para que se adapten al Junit 4, me dije, porque no publicarlo en Cristalab que es una comunidad que me dio tanto con todas las buenas intenciones. Por otro lado no cambié el ejemplo por me
pareció correcto ese y ya que me base en el trabajo de otra gente, estaba mal cambiar su trabajo.

Por otro lado no juzgues mi forma de usar Internet por un simple tutorial, ya que yo nunca juzgue tus aportes aquí, sino que los valore mucho ya que tengan la forma que tengan, o tomen las fuentes que sean, siempre aportan al que no conoce del tema.
Muchas gracias por tú opinión y no hay problema, no lo publiques, que lo haga otro que a lo mejor sabe más del tema.

Por alvarogili

11 de clabLevel



Genero:Masculino  

Desarrollo de software

firefox
Citar            
MensajeEscrito el 19 Abr 2012 05:08 pm
Todos copiamos en parte, la diferencia es lo que aportamos ... si no aporta, mejor citar las fuentes, evitamos ruido y contribuimos a la ecología de la Web, coincido con Mariux. En lo de tu trabajo te felicito, y si te subieron el sueldo mucho mejor

Jorge

Por solisarg

BOFH

13669 de clabLevel

4 tutoriales
5 articulos

Genero:Masculino   Bastard Operators From Hell Premio_Secretos

Argentina

firefox

 

Cristalab BabyBlue v4 + V4 © 2011 Cristalab
Powered by ClabEngines v4, HTML5, love and ponies.