Como se había dicho anteriormente, JUnit es una librería de código libre que se basa en anotaciones, utilizado en la automatización de pruebas unitarias y cualquier otro tipo de testing automatizado para aplicaciones desarrolladas en Java, JUnit permite
la ejecución de clases controladamente para evaluar el correcto funcionamiento de sus métodos, retornando una respuesta exitosa o un fallo a este, de acuerdo al valor de entrada.
Definición de cada modulo:
Módulo JUnit Platform: es la base para lanzar pruebas de framework en la máquina virtual de Java (JVM), permitiendo definir un TestEngine API (interfaz de JUnit que permite el descubrimiento y ejecución de pruebas en un modelo de programación particular) para desarrollar un marco de prueba que se ejecuta en la plataforma. Este módulo posee además soporte para los IDE: IntelliJ IDEA, Eclipse, Netbeans, Visual Studio Code y herramientas de compilación como (gradle, Maven y ant).
Módulo JUnit Jupiter: sería la combinación del nuevo modelo de programación y un modelo de extensión para escribir pruebas y extensiones en JUnit, provee un TestEngine basado en pruebas de la plataforma.
Módulo Junit Vintage: provee un TestEngine para correr Junit 3 y Junit 4 basado en pruebas de la plataforma, ahora bien, hablar de JUnit nos exige manejar varios conceptos y sus derivaciones como: estructura de métodos, anotaciones y asserts (o en su defecto, afirmaciones).
Estructura de métodos
JUnit admite la clase de test con la estructura de sus 4 tipos de métodos posibles, los cuales se enunciarán a continuación.
Una anotación es un carácter especial, que se ha incluido desde la versión 4 de JUnit, para intentar simplificar más la labor del programador. Se trata de palabras clave que se colocan antes de los métodos definidos e indican a las librerías JUnit instrucciones concretas; (algunas anotaciones, son opcionales y su uso depende de las exigencias de cada aplicación).
En las siguientes líneas, veremos las anotaciones más usadas en las pruebas unitarias.
Después de tener aplicado en nuestro código las anotaciones con sus respectivos métodos, es necesario comprobar los resultados que se obtendrán. Por lo anterior, la clase Assert dispone de una lista de funciones que ayudaran en dicho proceso. Estas funciones comparan el valor obtenido con el valor esperado lanzando excepciones si no son iguales. A continuación, se hace la relación entre la estructura de los métodos con su respectiva descripción.
|
Método |
Descripción |
|
assertTrue([mensaje], condición booleana) |
Verifica que la condición sea verdadera |
|
assertFalse([mensaje], condición booleana) |
Verifica que la condición sea falsa |
|
assertEquals([mensaje], valor esperado, valor obtenido) |
Comprueba que dos valores sean iguales |
|
assertSame([mensaje], valor esperado, valor actual) |
Valida que ambos parámetros sean el mismo objeto |
|
assertNotSame([mensaje], valor esperado, valor actual) |
Valida que los parámetros no sean el mismo objeto |
|
assertNull([mensaje], objeto) |
Comprueba que el objeto sea nulo |
|
assertNotNull([mensaje], objeto) |
Valida que el objeto no sea nulo |
JUnit está disponible en algunas herramientas de desarrollo como Netbeans y Eclipse las cuales poseen plug-ins que admiten la generación de plantillas para la creación de las pruebas de una clase Java automáticamente. En la siguiente tabla, se hace la generación de una plantilla usando JUnit en sus versiones 4 y 5 de una clase calculadora que posee los métodos básicos de suma, resta, multiplicación y división.
|
JUnit4 en eclipse |
JUnit5 en eclipse |
package test; import static org.junit.Assert.*; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; public class CalculadoraTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @AfterClass public static void tearDownAfterClass() throws Exception { } @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testSumar() { fail("Not yet implemented"); } } |
package test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class CalculadoraTest { @BeforeAll static void setUpBeforeClass() throws Exception { } @AfterAll static void tearDownAfterClass() throws Exception { } @BeforeEach void setUp() throws Exception { } @AfterEach void tearDown() throws Exception { } @Test void testSumar() { fail("Not yet implemented"); } } |
Nótese que, para ambos casos, la plantilla generada está acorde con los estándares de nombramiento de clases y métodos, además de incluir la estructura de métodos permitidos por JUnit como el setUp, tearDown, etc. y las anotaciones básicas.
Un aspecto importante sobre JUnit, es que permite realizar muchas pruebas a la vez, es decir, si tenemos varias clases a las cuales debemos hacer pruebas unitarias, en el proceso normal tendríamos que acceder a cada una y ejecutarlas; para evadir ese proceso largo y tedioso, JUnit nos ofrece JUnit Test Suite que nos permite correr todas las clases de prueba a la vez.
Aplicación
Vista la teoría es necesario replantearla y aplicar dichos conceptos a la realidad, y que mejor manera que presentando un ejemplo para asignación de notas a un estudiante. El entorno utilizado para éste, será Eclipse, por lo tanto, no será necesario descargar
el paquete de instalación de JUnit ya que el IDE lo trae consigo. Sin embargo, si se desea utilizar otro entorno de desarrollo que carezca de JUnit por defecto, puede visitar la página oficial y descargar la versión que desee. El enlace a continuación
lo re direccionará a la descarga de la versión 5 de JUnit https://junit.org/junit5/
Haciendo uso de JUnit Test Case
Lo primero que vamos hacer, es crear un nuevo proyecto Java, llamado SistemaBasicoNotas, con sus respectivas clases, para este caso, Estudiante y Boletin.

Para el ejemplo, el código fuente será el siguiente.
|
Clase Estudiante |
package main; public class Estudiante { public String id; public String nombreCompleto; public String sexo; public String getNombre () { return nombreCompleto; } public boolean blankSpaceValidation () throws Exception { boolean validation; if (id !="" && nombreCompleto != "" && sexo !="") { validation= true; }else { validation = false; throw new Exception("Por favor, no dejes valores" + " en blanco al momento de crear un estudiante"); } return validation; } } |
|
Clase Boletín |
package main; public class Boletin { public String idBoletin; public Estudiante estudiante; //Inicialización de variables static int MAXMATERIA = 5; int indexArrayMateria= 0; double [] notas = new double[MAXMATERIA]; double suma=0; int contador=0; double resultado=0; public boolean blankSpaceValidation () throws Exception { boolean validation; if (idBoletin !="") { validation= true; }else { validation = false; throw new Exception("Por favor, no dejes valores en " + "blanco al momento de crear un nuevo boletin "); } return validation; } public void guardarNotas (double nota) throws Exception { if(indexArrayMateria<MAXMATERIA ) { notas [indexArrayMateria]= nota; indexArrayMateria ++; }else { throw new Exception("Lo sentimos, pero el estudiante no " + "puede tener más de 5 notas, por solo tener 5 materias " + "registradas en el sistema"); } } public double calcularPromedio () { for (int i = 0; i < notas.length; i++) { suma+=notas[i]; contador+=1; } resultado=suma/MAXMATERIA; return resultado; } } |
Una vez creadas las clases e implementado el código, debemos hacer uso de JUnit5 para realizar las pruebas, para ello, debemos dar click derecho sobre la clase a la cual se le harán las pruebas, seleccionamos “New” y luego “Other” como se muestra a continuación.
Nota: En algunos casos JUnit Case, se presenta una vez seleccionado “New”, como aparece en la imagen.

Cuando seleccionamos en “Other”, se abrirá una nueva ventana. Ahora solo basta buscar “JUnit”, seleccionar “JUnit Test Case” y dar click en “Next”

Una vez seleccionado “Next”, se nos abrirá una nueva ventana para configurar JUnit Test Case.
Cuando hayamos revisado los puntos, damos clic en “Next”

La ventana que se nos abrirá al dar siguiente será la que nos pedirá los métodos de la clase que vamos a crear para realizarle las pruebas. En el caso nuestro, seleccionaremos todos y finalizamos.

Al ser primera vez que utilizamos la librería de JUnit, nos pedirán que agreguemos la librería de JUnit5 al build path del proyecto, para ello lo seleccionamos y damos OK

En este punto, ya tenemos nuestra clase de prueba, con los métodos básicos que admite JUnit y los métodos propios de la clase que elegimos.
package test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class BoletinTests { @BeforeAll static void setUpBeforeClass() throws Exception { } @AfterAll static void tearDownAfterClass() throws Exception { } @BeforeEach void setUp() throws Exception { } @AfterEach void tearDown() throws Exception { } @Test void testBlankSpaceValidation() { fail("Not yet implemented"); } @Test void testGuardarNotas() { fail("Not yet implemented"); } @Test void testCalcularPromedio() { fail("Not yet implemented"); } }
A modo de comprender que sucede con las anotaciones, vamos a borrar los assert fail de cada método de la clase y hacemos un System.out.println() en los métodos de todas las anotaciones. El código debe quedar de la siguiente manera.
package test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import main.Boletin; import main.Estudiante; class BoletinTest { @BeforeAll static void setUpBeforeClass() throws Exception { System.out.println("Inicialización de variables antes de iniciar los tests\n"); } @AfterAll static void tearDownAfterClass() throws Exception { System.out.println("\nSe ejecuta para limpiar el entorno despues de todos los tests"); } @BeforeEach void setUp() throws Exception { System.out.println("Inicialización de variables antes de iniciar cada test"); } @AfterEach void tearDown() throws Exception { System.out.println("Se ejecuta para limpiar el entorno despues de cada tests\n"); } @Test void testBlankSpaceValidation() { System.out.println("****Ejecuta la prueba 1"); } @Test void testGuardarNotas() { System.out.println("****Ejecuta la prueba 2"); } @Test void testCalcularPromedio() { System.out.println("****Ejecuta la prueba 3"); } }
Para ejecutar JUnit solo basta dar clic derecho sobre la clase de prueba que generamos, Run As y JUnit test.

Analicemos el resultado generado, de acuerdo a la teoría vista.

Otro ejemplo de una anotación que puede servir es el @Disabled, el cual da la instrucción a JUnit de que ese método de prueba no se va a ejecutar.
@Test void testCalcularPromedio() throws Exception { System.out.println("*** Aquí se ejecuta el método de calcular promedio"); } @Disabled void testBlankSpaceValidation () throws Exception { System.out.println("*** Aquí se ejecuta el método de validación de espacios"); }
Observe que para el ejemplo hacemos uso del disabled para el test de validación de espacios, por lo cual, el resultado debe ignorar ese método y solo ejecutar el testCalcularPromedio.

Es momento de analizar el funcionamiento de algunos asserts vistos, para ello generamos la prueba a la clase Estudiante como se hizo anteriormente con la clase Boletín.
AssertEquals para
tipos String:
Una vez realizado lo anterior, creamos un objeto de la clase Estudiante. Para corroborar que el nombre si se ha guardado correctamente, hacemos un assertEquals con el valor esperado y el arrojado por el sistema con el getNombre() acompañado de un mensaje que nos avisara cuando el nombre no coincida
@Test void testGetNombre() { //Creamos un nuevo objeto estudiante con los datos respectivos Estudiante estu1= new Estudiante(); estu1.id="102456258"; estu1.nombreCompleto="Andrés Rafael"; estu1.sexo="Masculino"; //definimos las variables para actual y esperado String actual = estu1.getNombre(); String esperado="Andrés Rafael"; //implementamos el assertEquals assertEquals("Los valores no coinciden", esperado, actual); }
Note que al correr JUnit sobre EstudianteTest, se abre en la parte inferior los resultados arrojados por JUnit. Presentando cero errores, cero fallos, el indicador de fallo en verde y el nombre de la clase. Lo que indica que tanto el nombre guardado como el consultado coinciden y no hubo algún error en el guardado de este atributo.

Si por error hubiéramos guardado el nombre “Andrés Rafael” y el valor de la variable esperado hubiera sido “Andres Rafael” el resultado hubiera generado un fallo, ya que Andrés es diferente a Andres. Una vez ejecutado el código, el resultado nos mostraría el indicador en rojo y en la traza de fallos, el error generado y el mensaje definido en el assert “Los valores no coinciden”.

AssertEquals para tipos double:
Para ejecutar este assert, haremos uso de BoletinTest del método testCalcularPromedio. Creamos el objeto de la clase estudiante y la clase Boletin. Llamamos a calcularPromedio() y usamos el asserEquals para verificar que el valor coincida con el esperado (4.5).
@Test void testCalcularPromedio() throws Exception { System.out.println("****Ejecuta la prueba 3"); //Creamos un nuevo Objeto Boletin Boletin bole1= new Boletin(); bole1.idBoletin="1"; bole1.guardarNotas(5.0); bole1.guardarNotas(5.0); bole1.guardarNotas(5.0); bole1.guardarNotas(5.0); double esperado = 4.5; double actual = bole1.calcularPromedio(); assertEquals(esperado, actual, 0.1); }
Es de aclarar que el promedio se realiza con el número total de materias, es decir, 5. Por tal motivo el resultado del assert crea un fallo por solo haberse registrado 4 notas además de no coincidir el promedio.

AssertTrue:
Otro assert es el assertTrue, que permite verificar si una condición es verdadera. Como en la clase se tiene un método que verifica que no exista espacios en blancos al momento de añadir el valor a los atributos, este arroja un true cuando los valores están llenos y false cuando se intenta guardar un objeto con algún atributo sin valor. Para el ejemplo, vamos a guardar un estudiante sin id (identificación).
@Test void testBlankSpaceValidation () throws Exception { //Creamos un nuevo Objeto estudiante Estudiante estu2= new Estudiante(); estu2.id=""; estu2.nombreCompleto="Mariana Rosales Franco"; estu2.sexo="Femenino"; //definimos variables para el assert boolean actual = estu2.blankSpaceValidation(); //implementamos el assertTrue assertTrue(actual); }
Al ejecutarlo, efectivamente nos lanza el error con el respectivo mensaje del throws Exception definido en el método de la clase de origen. Note que como se tienen dos test, el resultado los muestra ambos; el testGetNombre con una buena calificación, y el testBlanckSpaceValidation con un error.

Sin embargo, si se añade la información correcta el resultado será exitoso. Dándonos como conclusión el correcto funcionamiento de los métodos

Haciendo uso de JUnit Test Suite
Ya vimos cómo hacer pruebas unitarias a una sola clase, ahora veremos, como hacerla a varias haciendo uso de JUnit Test Suite. Siguiendo el ejemplo anterior y suponiendo que vamos a realizar las pruebas a cada clase generada, damos clic derecho sobre nuestro proyecto seleccionamos “new” y luego “Other” como se muestra en la siguiente imagen.

Consecuentemente, eclipse abrirá la siguiente ventana donde seleccionaremos “Java”, “JUnit”, “JUnit Test Suite” y finalmente, “Next”.

En la próxima ventana, dejamos seleccionado “New JUnit4 suite” seleccionamos el paquete donde va a quedar la clase generada, asignamos el nombre de ella y damos “Finish”.

La clase generada, tendrá la anotación de @RunWith (Suite.class) y @SuiteClasses ({}) sobre la clase AllTest, sin embargo, para que corra sobre JUnit 5 suite, debemos cambiar las anotaciones anteriores por @RunWith (JUnitPlatform.class) y @SelectClasses ({}).Consecuentemente, añadimos las clases que queremos incluir en la anotación @SuiteClasses, para nuestro caso, BoletinTest y EstudianteTest.
package test; import org.junit.platform.runner.JUnitPlatform; import org.junit.platform.suite.api.SelectClasses; import org.junit.runner.RunWith; @RunWith(JUnitPlatform.class) @SelectClasses({BoletinTest.class, EstudianteTest.class}) public class AllTests { }
Finalmente solo bastará con ejecutarla y tendremos un resultado exitoso en caso de haber pasado cada uno de las pruebas unitarias a las clases vinculadas, en caso contrario, aparecerá el indicador de color rojo y podremos ver todas las clases de prueba y aquellas que fallaron.
