Crear una prueba unitaria
La mayoría de IDEs proporcionan un sistema para crear pruebas unitarias de JUnit debido a que tienen integración completa. Típicamente la encontramos en el menú File | New o similares, o bien en algunos IDEs puede ser una opción que nos proponga directamente haciendo clic derecho desde el explorador de clases del proyecto sobre un archivo Java del que queramos crear una prueba.
Esto es interesante porque buena parte de los IDEs también van a tener un asistente para leer la información de la clase que queremos testear y nos van a ofrecer la posibilidad de crear métodos automáticamente. También muchos nos van a permitir crear automáticamente otros métodos del ciclo de vida de un test, como los métodos Before y After, o los métodos BeforeClass y AfterClass. Todos estos métodos van a ser estudiados posteriormente en este taller.
Qué hay dentro de un test de JUnit 4
Los tests de JUnit 4 no son más que clases Java normales y corrientes, con métodos públicos que normalmente tendrán una signatura que comienza como public void, aunque algunos métodos serán estáticos y por lo tanto tendrán una signatura que comenzará como public static void.
JUnit 4 se basa en anotaciones, que son partículas especiales que comienzan con el caracter @ y que se escriben antes de la declaración de un método o de una clase. Es posible que ya conozcas las anotaciones si has trabajado lo suficiente con Java, debido a que @Override es la anotación típica que nos encontraríamos al usar herencia y sobreescribir métodos. Las anotaciones que vamos a ver en JUnit son muy parecidas a ésta.
Por ejemplo, para poder crear un test en JUnit 4, marcaremos nuestros métodos con la anotación @Test. Al momento de poner esta anotación antes de un método, ya le instruye a JUnit para que trate ese método como si fuese un método con tests, y por lo tanto, será ejecutado cuando se lance el runner.
De modo que un test en JUnit podría tener el siguiente aspecto:
import org.junit.Test;
import static org.junit.Assert.*;
public class ExampleTest {
@Test
public void testVacio() {
fail("Este test está en blanco");
}
}
En este caso, la clase ExampleTest tiene un test (porque lo hemos etiquetado con la anotación @Test). Este test dentro lleva una llamada a la función fail(). Típicamente en JUnit haremos un import static de toda la clase org.junit.Assert.*. Al principio puede ser comlpicado de identificar, pero este import permite usar todos los métodos estáticos de esa clase, como fail() o como assertEquals(), sin tener que poner Assert. delante. Es más conveniente para ahorrar tiempo, pero puede provocar que al principio nos preguntemos de dónde sale ese fail() mágico.
Y fail() no es más que un aserto de JUnit que siempre va a fallar cuando se ejecuta. Los asertos hacen comprobaciones. Por ejemplo, tenemos asertos que prueban que dos cosas son iguales o que una variable es verdadera. Imagínalos como un if glorificado donde si el if es verdadero, se continúa con la ejecución del test, pero si el if es falso, se provoca una excepción. Esa excepción hará que la ejecución del test se detenga y que JUnit marque esa función de color rojo, indicando que no se ha podido completar correctamente y reportando que el test tiene un error.
assertEquals
fail() no es el aserto más interesante del mundo porque aunque habrá ocasiones donde queramos que el mero hecho de alcanzar una línea de código provoque un error (me estoy imaginando un catch para probar que un código se ejecuta sin lanzar una excepción), lo normal será que usemos los atajos que nos proporciona JUnit dentro de la clase Asserts.
Por ejemplo, con assertEquals podemos probar que dos expresiones son iguales. Se trata de una función que va a tomar dos parámetros. Uno de ellos será el resultado de llamar a una función de nuestro código, y el otro será lo que debería devolver esa función. Normalmente, pondremos primero el valor esperado, y después el valor recibido.
Es importante cuando hagamos esto que tratemos al valor esperado como algo estático para reducir el riesgo de que lo escribamos mal. Si hay algo peor que no tener tests, es tener un test que no funciona bien debido a que el valor esperado también tiene errores. Los casos de prueba de un test deberían ser escritos con cautela y simplicidad para asegurarnos de que, si hay errores, estos están en el código recibido (lo que obtenemos al llamar a una función que estamos probando), y no en los asertos esperados, que se supone deberían estar bien.
Sea como sea, con assertEquals tenemos a nuestra disposición un atajo que nos permite lanzar un error que marcará el test como inválido excepto si ambas expresiones son iguales. Si ambas son iguales, sobreviviremos al aserto y podremos seguir ejecutando más. Si alcanzamos el final del método marcado como test, entonces se considerará que el test ha sido un éxito.
@Test
public void testCustomer() {
Customer cus = new Customer("Juan", "Palomo");
assertEquals("Juan", cus.getName());
assertEquals("Palomo", cus.getSurname());
}