🇺🇦 Слава Україні! Consulta cómo puedes ayudar a Ucrania desde España u otros países en supportukrainenow.org.

JUnit 4

Tu primera prueba de JUnit

• Duración: 6:59 • #java #testing #junit #unit-testing

En este episodio creamos una prueba unitaria usando JUnit, y así vemos cómo funciona la anotación Test y las funciones fail() y assertEquals(). JUnit incorpora un montón de asertos, como assertEquals(), y muchos de ellos se caracterizan por tener al menos dos parámetros: expected, para representar el valor que debería devolver la llamada a la función de nuestro programa o biblioteca, y actual, para compararlo contra el valor real que se obtiene de su ejecución. En este vídeo, vemos también cómo ejecuta Eclipse las pruebas utilizando su interfaz gráfica.

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());
}
Desplegar transcripción del episodio

Hola a todos, qué tal como estáis, y bienvenidos al episodio número 2 de este tutorial de JUnit. En este episodio voy a crear la prueba unitaria de JUnit que prometí en el episodio anterior, y vamos a probar de forma rápida estas dos funciones, pero de una forma más automatizada.

En primer lugar voy a crear mi archivo de JUnit, y para ello lo mejor que puedo hacer es simplemente crear con el botón derecho un nuevo archivo de tipo JUnit Test Case. En el caso de que no lo veáis, siempre podéis dar a Other, y buscar aquí JUnit, y acabaréis encontrándolo. Si estáis utilizando NetBeans, de forma parecida seguramente encontraréis en alguna parte del menú New la forma de crear una prueba unitaria, y si no seguramente también el propio menú New recomendará crear una prueba unitaria de alguna manera.

De momento vamos a crear una Test Case, pero ya iremos viendo cómo se puede hacer más cosas más adelante. Me pregunta que qué quiero crear, si una prueba de JUnit 3 o una prueba de JUnit 4. Yo voy a enseñar JUnit 4 en esta lista de reproducción así que no desmarquéis esto bajo ningún concepto. Eclipse aquí nos pregunta muchísimas cosas: el nombre, la superclase, qué métodos crear, qué clase vamos a probar... y es porque está tan integrado dentro de Eclipse que podemos hacer ya que Eclipse nos cree parte del código de la prueba unitaria para no tener que escribir tanto. Esto es algo que más adelante haremos, pero como por el momento me quiero centrar en explicar la sintaxis de la librería y sus funciones y tal, de momento no voy a marcar nada. Simplemente voy a indicar aquí el nombre de mi clase, que va a ser Calculadora, y por costumbre se le suele poner Test para indicar que es una prueba. Y le voy a dar a Finish para que termine. Y como veis en este caso me pregunta si quiero agregar JUnit 4 al build path, es decir, si quiero que se agregue como librería. Es necesario, evidentemente, porque JUnit no forma parte de Java, así que tendremos que agregarlo para que podamos utilizar esta librería.

Y como veis, lo primero que se nos muestra es esto: una clase llamada CalculadoraTest con una serie de imports ya hechos y con este método llamado test(), que como veis se con extraña cosa. Si nunca lo habéis visto, a lo mejor resulta raro: esto es una anotación, y en este caso este método está anotado con la palabra Test, o con la anotación Test más bien. Con esto lo que se hace es marcar este método como una prueba, y esto está muy bien porque de este modo JUnit puede reconocer automáticamente métodos que sean pruebas. Cualquier método public void que lleve la anotación Test encima, será reconocido por JUnit como prueba unitaria. Y aquí como veis se ha creado una función, una llamada una función, llamada fail(), que realmente es assert.fail(), lo que pasa es que está hecho un import static para que no tengamos que escribir ese assert, que muestra un mensaje llamado Not yet implemented. Entonces, antes de empezar a escribir, yo lo que voy a hacer es correr a esta prueba unitaria. Para ello, qué mejor forma que darle botón derecho, buscar Run As, y aquí marcar como JUnit Test, ¿de acuerdo? Y como veis aquí pasa una cosa interesante en el IDE, y es que aparece una nueva pestaña llamada JUnit. Por eso os he dicho que estaba muy bien esto,porque los IDEs lo integran bastante bien. Nos va a mostrar los distintos problemas que ha encontrado con nuestra prueba unitaria, y como veis nos aparece en nuestra CalculadoraTest, nos aparece nuestro método test() que es la prueba Test, y aquí nos muestra por qué ha fallado, porque además nos sale de color rojo: ha fallado, ¿que ha podido pasar? Bueno, evidentemente falla porque se está haciendo una llamada al método al método fail(). He aquí la primera lección de JUnit: si escribís una llamada a fail(), automáticamente la prueba fallará.

Quiero probar estos dos métodos que había creado aquí suma y resta. Y para ello, lo que voy a hacer es crear dos métodos públicos y de tipo void, respectivamente: testSuma y testResta, ¿de acuerdo? Y para reconocerlos como pruebas les voy a agregar la anotación Test, para que JUnit los pueda reconocer como una prueba. Y ahora aquí lo que voy a hacer es lo siguiente: para hacer una prueba, lo más sencillo y lo más común es simplemente intentar hacer una llamada a una función, que a ser posible debería ser lo más corta posible para poder probar una única cosa y no tener que probar cosas colaterales ni nada por el estilo. Entonces en este caso yo lo que voy a hacer es una llamada a la función suma(), voy a guardar el resultado de llamar al calculadora.suma(2, 3). Esta función me va a devolver un resultado que yo tengo que determinar de antemano cuál es. Por ejemplo, esperado, se supone que si yo somos 2 + 3, me tiene que dar 5. De todos modos, pongo un comentario por si alguien lo está dudando. Ahora lo único que tengo que hacer es pedirle a JUnit que pruebe si el resultado y esperado es lo mismo. Entonces, para eso JUnit me ofrece una serie de funciones que empiezan por assert, como asertArrayEquals, assertEquals, assertNotEquals, assertNull... hay un montón de asserts que iremos considerando más adelante, pero por ahora uno sencillo es assertEquals(), que sirve para comprobar que dos cosas son exactamente iguales. Entonces como veis hay assertEquals para todo: está para Double, está para Long, para Object... de alguna manera siempre podemos probar cualquier tipo de cosa. Además todos veis que tienen dos parámetros. Bueno, algunos tres pero la mayoría tienen como parámetro un expected y un actual. Expected, actual, expected, actual... Expected, actual, delta... etcétera, etcétera.

La idea es la siguiente: yo voy a hacer una llamada a este assertEquals, y en expected lo que voy a hacer es decirle el nombre de la variable que contiene el resultado esperado, por ejemplo, esperado. Y el resultado lo que voy a hacer es ponerlo en el nombre de la otra variable, en actual, que es básicamente lo que ha obtenido. Realmente da igual como lo queráis hacer vale pero lo más común y lo más habitual y lo más recomendable es seguir los nombres de los parámetros y llamar a la función assertEquals con el valor que debería devolver en principio, y después del valor que realmente ha devuelto, ¿vale? Realmente no importa mucho pero bueno es lo más conveniente hacerlo así, pues porque lo dice la función.

De forma parecida voy a hacer int resultado = calculadora.resta(3, 2), da igual realmente, pero bueno. Se supone que si yo hago 3 - 2, lo que me debe devolver es 1, ¿no es así? Entonces de forma parecida yo aquí puedo hacer un assertEquals que me compruebe que esperado y resultado sean lo mismo. Hecho esto, yo puedo correr mi prueba, y aquí como veis ya me dice que está bien. Sale todo de color verde y me dice que mis pruebas están correctas, porque aparece un tick. Si hubiese cometido algún error, pongamos que por ejemplo me equivoco con los operadores, JUnit se hubiese enterado rápidamente, porque al correrlo todo hubiese fallado.

Esto está muy bien porque de este modo nosotros podemos tener pruebas hechas, y si cambiamos código parcialmente de vez en cuando nos podemos dar cuenta que, a lo mejor, algo se ha roto a partir de algún cambio determinado que hayamos hecho, o cosas por el estilo.