JUnit: Herramienta indispensable para el desarrollo Java
Hoy voy a hablar de una herramienta que debería ser de uso común para el desarrollo. Estoy hablando de JUnit, la librería de pruebas unitarias más utilizado en entornos Java.
Las pruebas unitarias consisten en desarrollar código para probar una determinada funcionalidad de nuestra aplicación.
Vamos a ver un pequeño ejemplo. Supongamos que estamos haciendo una librería matemática que incluye una funcion para calcular el factorial de un número. Podría ser una clase parecida a la siguiente:
package org.tcymu.util;
public class MathLibrary {
public static int factorial(int n) throws IllegalArgumentException {
int response = 1;
if (n < 0) {
throw new IllegalArgumentException();
}
if (n > 0) {
response = n * factorial(n - 1);
}
return response;
}
}
En esta entrada voy a utilizar las facilidades que da Eclipse gracias a su integración con JUnit. Para ello en la vista package sobre la clase que queremos probar hacemos botón dereco -> “New” -> “JUnit Test Case”.
Nos aparece la siguiente ventana en la que seleccionamos “New JUnit 4 test” (tened en cuenta que JUnit 4 necesita Java 1.5 o superior).
Podemos ver que nos propone un nombre para la clase de pruebas, así como un paquete y una carpeta de fuentes (por defecto propone el mismo paquete que las fuentes, aunque podríamos elegir otro). También podemos seleccionar que nos cree los siguientes métodos de apoyo para preparar el entorno de los test o liberar recursos:
- Métodos setUp y tearDown. Los ejecuta antes de llamar a cada método de prueba en esa clase. La secuencia sería setUp, metodo1Test, tearDown, setUp, metodo2Test, tearDown.
- Métodos setUpBeforeClass y tearDownAfterClass. Estos métodos se ejecutan antes y después de todos los métodos de la clase. La secuencia sería setUpBeforeClass, metodo1Test, metodo2Test, tearDownAfterClass.
A continuación nos pide los métodos que queremos probar. En este ejemplo seleccionamos el método que queremos probar (factorial) y ninguno de los métodos de apoyo (en nuestro sencillo ejemplo no necesitamos crear ni liberar nada).
Tras finalizar y si no tenemos la librería JUnit 4 en el Build Path nos la añade. Y por último crea el esqueleto de la clase de prueba:
package org.tcymu.util;
import static org.junit.Assert.*;
import org.junit.Test;
public class MathLibraryTest {
@Test
public void testFactorial() {
fail("Not yet implemented");
}
}
Hay que destacar que lo que realmente convierte al método en un test que ejecutará JUnit es la anotación Java @Test, al igual que lo que marcaría a los métodos de apoyo serían anotaciones como @BeforeClass, @AfterClass, @Before y @After.
Podemos observar que el método testFactorial sólo contiene la línea fail("Not yet implemented"); , por lo que si ejecutamos el test (mediante botón derecho sobre la clase de pruebas y “Run As” -> “JUnit Test” se nos abre la vista de JUnit con el siguiente resultado:
Por tanto es hora de implementar nuestra prueba para pasar la barra al ansiado color verde. Básicamente se hacen comprobaciones de los resultados esperados frente a los recibidos mediante la clase org.junit.Assert (documentación Javadoc de JUnit).
package org.tcymu.util;
import static org.junit.Assert.*;
import org.junit.Assert;
import org.junit.Test;
public class MathLibraryTest {
@Test
public void testFactorial() {
Assert.assertEquals(1, MathLibrary.factorial(0));
Assert.assertTrue(1 == MathLibrary.factorial(1));
Assert.assertEquals(24, MathLibrary.factorial(4));
Assert.assertEquals(720, MathLibrary.factorial(6));
boolean excepcionLanzada = false;
try {
MathLibrary.factorial(-1);
} catch (IllegalArgumentException e) {
excepcionLanzada = true;
}
Assert.assertTrue(excepcionLanzada);
}
}
Vemos que utilizamos varios métodos para comprobar que se obtiene el resultado esperado. También podemos ver cómo probamos que se lanza la excepción esperada cuando el argumento no es válido (creo haber leído en algún sitio que se iba a mejorar la prueba de excepciones en próximas versiones, pero no consigo localizar la noticia).
Una vez que se ejecutan la prueba con éxito (la barrita verde) sabemos que el método funciona como nosotros esperamos. Ahora tras cualquier cambio en el código volveríamos a ejecutar JUnit para comprobar que no hemos roto nada. Esto nos da una gran seguridad a la hora de meter mano o refactorizar métodos complejos.
Por último no quisiera terminar la entrada sin nombrar un par de temas relacionados con las pruebas unitarias.
- Una buena prueba debe ser repetible (se debe de poder lanzar cuantas veces queramos sin afectar a nada). Por ello cada vez más se automatizan las pruebas en los procesos de integración continua de forma que antes de generarse una versión de una aplicación se corren todas las pruebas para dicha aplicación.
- Existe un modelo de desarrollo que promueve que primero se escriban las pruebas y después el código. Es el llamado Desarrollo Guiado por Pruebas o Test Driven Development (TDD).
Espero que os haya gustado esta pequeña introducción.
Add comment 23 Octubre 2009
Pequeña introducción a Git
Git es un sistema de control de versiones al igual que CVS, Subversion y otros.
Git fue diseñado por Linus Torwalds (creador de Linux) para utilizarlo en el desarrollo del núcleo de Linux. En su sección de descargas podemos encontrar entre otras, enlaces a versiones para Linux (en rpm o deb), MacOS y Windows (a través de Cygwin o del proyecto MSysGit que provee instalables completos e incluso una versión portable).
Si venimos desde un enfoque más clásico como CVS o Subversion, la principal diferencia que aporta Git es que es un sistema distribuido. ¿Y qué quiere decir distribuido?. Pues que a diferencia de CVS o Subversion podemos trabajar con nuestro control de versiones aunque no estemos conectados a una red, ya que es como si tuviésemos el servidor en nuestra propia máquina. De esta forma está diferenciado lo que son las acciones con nuestro repositorio y las que llevamos cabo con repositorios remotos (ese sería el estilo CVS).

En principio es una solución muy recomendable si queremos mantener un versionado en nuestra máquina de desarrollo (en este caso sólo utilizaremos los comandos entre desarrollo y el repositorio propio del esquema. Vamos a ver un pequeño resumen de los comandos que utilizaríamos en este caso.
- Lo primero que necesitamos es configurar nuestro usuario:
git config --global user.name "Don Nadie"
git config --global user.email "don.nadie@test.com" - Para crear un repositorio nos situaremos en el directorio principal de nuestro proyecto (o en uno vacío si es un proyecto nuevo) y haremos:
git inity si el proyecto está empezado añadiremos los archivos mediante
git add .
git commit -m "Mensaje"(Si no se le pasa -m nos pedirá un mensaje, ya que es obligatorio)con lo que ya tendremos todo nuestro proyecto bajo el control de versiones.
- Para el ciclo de desarrollo normal, primero se añaden los cambios al índice (es como un almacén intermedio que almacena todos los cambios) y luego lo persistiremos en el repositorio.
git add ruta/ficheroAñade el fichero nuevo o modificado al índice
git commitPersiste los cambios que tenemos en el índice al repositorio (nos pide mensaje)
git commit -aHace el paso al índice y el commit en un solo paso - Para ver el estado del desarrollo podemos utilizar los siguientes comandos:
git statusMuestra el estado de la rama de desarrollo
git diffMuestra las diferencias entre la rama de desarrollo y el índice
git diff --cachedMuestra las diferencias entre el índice y el HEAD (último commit)
git diff HEADMuestra las diferencias entre la rama de desarrollo y el HEAD
git logNos muestra un historial de los commits del repositorio - El trabajo con ramas es muy sencillo en Git.
git branch testCrea una rama de nombre “test” a partir de la actual
git branchNos muestra las ramas existentes y la rama en la que nos encontramos (cuando hacemos git status también nos muestra la rama en la que nos encontramos)
git checkouttest Nos sitúa en la rama test
git merge testSi nos hemos situado en la rama master (la rama principal, en la que empezamos) nos combina los cambios en la rama test con esta rama
Git también tiene gran potencia para compartir el código con otros desarrolladores, aunque este caso lo dejaremos para otra entrada.
Por último no quisiera terminar esta entrada sin decir que Git no es el único control de versiones distribuido. También Mercurial o Bazaar nos pueden servir para los mismos fines e incluso pueden ser más sencillas si estamos acostumbrados a CVS.
Add comment 3 Septiembre 2009
Estructura de directorios en Linux
En esta entrada vamos a intentar explicar un poco la estructura de directorios en Linux, concretamente la que se define en el FHS (Filesystem Hierarchy Standar) que es un estándar definido por un grupo de organizaciones (entre ellas empresas como HP, Red Hat o IBM). Eso sí, luego cada distribución es un mundo, y los estándares no se siguen al 100%.
Si listamos el contenido del directorio raiz en nuestro Linux (mediante cd / nos situamos en el raiz y con ls hacemos el listado) veremos algo similar (en este caso es mi Xubuntu a lo siguiente.

Los directorios que nos encontramos son los siguientes:
- bin: Es el directorio en el que encontramos los principales ejecutables del sistema.
- sbin: Contiene ejecutables reservados al superusuario.
- boot: El directorio boot contiene los elementos necesarios para el arranque del sistema.
- dev: En Linux los dispositivos como particiones de discos duros, modems, terminales y demás se representan como un fichero. El directorio dev continene dichos elementos (devices en inglés).
- etc: Este directorio contiene la configuración de nuestro sistema.
- home: Dentro de este directorio se encuentran los directorios de los distintos usuarios del sistema. Es algo similar al Documents and Settings de los sistemas Windows.
- lib: En este directorio se encuentran librerías de uso común por distintas aplicaciones como los ejecutables de bin y sbin.
- media: En media se suelen montar los elementos no permanentes tales como memorias usb o cdroms. Este es un directorio de relativamente uso reciente, aunque yo las distribuciones que uso ya lo utilizan.
- mnt: Este directorio antiguamente se utilizaba para montar casi todo. Hoy en días según el FHS se debe utilizar para montajes temporales por parte del administrador.
- opt: En este directorio se debería instalar el software de terceras partes. Sería algo similar al “Archivos de Programa” o “Program Files” de Windows.
- proc: Este es un directorio virtual en el que el núcleo y otros procesos muestran su estado. Por ejemplo el archivo uptime mantiene el tiempo que lleva en funcionamiento el sistema.
- root: Es el directorio personal del superusuario.
- srv: En srv según el estandar se deberían situar los ficheros que sirve nuestro sistema (a través de un servidor web o ftp por ejemplo). Sin embargo no está demasiado difundido su uso.
- sys: Otro directorio virtual que es utilizado por los elementos conectados al sistema, como los elementos Plug and Play.
- tmp: Es el directorio de uso temporal del sistema.
- usr: Este directorio es toda una estructura de directorios estáticos (no varían) que contiene tanto software como otros recursos. Podría ser compartido entre varios sistemas.
- var: Otra gran estructura de directorios, aunque contrariamente a usr, la información que se almacena en var es variable, como por ejemplo los logs del sistema.
Como podemos ver, no es una estructura sencilla ni especialmente intuitiva, por lo que no es de extrañar que algunas distribuciones como por ejemplo Gobolinux utilicen una estructura completamente diferente.
Add comment 24 Julio 2009








