JUnit Parameterized Test

El concepto de JUnit Parameterized Test es un concepto relativamente nuevo y pertenece a JUnit 5. Cuando realizamos pruebas unitarias en muchas ocasiones nos encontramos con la necesidad de realizar el mismo test pasando diferentes grupos de parámetros. Vamos a ver un ejemplo sencillo de cómo esto funciona. El primer paso que deberemos hacer es construir un proyecto Maven y con él añadir las dependencias necesarias de Junit para crear JUnit Parameterized Test.

<dependency>
   <groupId>org.junit.jupiter</groupId>
   <artifactId>junit-jupiter-api</artifactId>
   <version>5.9.0</version>
   <scope>test</scope>
  </dependency>

  <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params -->
  <dependency>
   <groupId>org.junit.jupiter</groupId>
   <artifactId>junit-jupiter-params</artifactId>
   <version>5.9.0</version>
   <scope>test</scope>
  </dependency>

Una vez realizado este primer paso el siguiente paso es actualizar el proyecto de Maven para que por lo menos trabaje con Java 1.8.

 <properties>
  <maven.compiler.target>1.8</maven.compiler.target>
  <maven.compiler.source>1.8</maven.compiler.source>
 </properties>

Hemos terminado de configurar el proyecto es momento de construir código y generar unas pruebas unitarias elementales. Para ello nos vamos a apoyar en la clase Nota . Esta clase se encarga de definir el concepto de nota y de devolvernos una calificación concreta dependiendo de la Nota que tengamos.

package com.arquitecturajava.models;

import java.util.Objects;

public class Nota {

 private String asignatura;
 private double valor;
 public String getAsignatura() {
  return asignatura;
 }
 public void setAsignatura(String asignatura) {
  this.asignatura = asignatura;
 }
 public double getValor() {
  return valor;
 }
 public void setValor(double valor) {
  if (valor<0 || valor>10) throw new RuntimeException("valor de nota no valido");
  this.valor = valor;
 }
 public Nota(String asignatura, double valor) {
  super();
  this.setAsignatura(asignatura);
  this.setValor(valor);
 }
 
 public String getCalificacion() {
  
  // sacame un mensaje cuando sea menor de cero
  // o mayor de 10
  if (valor>=0 && valor<=3) {
   
   return "MuyDeficiente";
  }else if (valor>3 && valor<5) {
   
   return "Insuficiente";
  }else if (valor>=5 && valor<6) {
   return "Suficiente";
  }else if (valor>=6 && valor<7) {
   
   return "Bien";
  }else if (valor>=7 && valor<9) {
   
   return "Notable";
  }else return "SobreSaliente";
  
  
 }
 @Override
 public int hashCode() {
  return Objects.hash(asignatura, valor);
 }
 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Nota other = (Nota) obj;
  return Objects.equals(asignatura, other.asignatura)
    && Double.doubleToLongBits(valor) == Double.doubleToLongBits(other.valor);
 }

 
}

La clave en este código la tenemos en el método getCalificacion().

Este método dependiendo del valor de la Nota nos devuelve Insuficiente, Notable etc.

public String getCalificacion() {
  
  // sacame un mensaje cuando sea menor de cero
  // o mayor de 10
  if (valor>=0 && valor<=3) {
   
   return "MuyDeficiente";
  }else if (valor>3 && valor<5) {
   
   return "Insuficiente";
  }else if (valor>=5 && valor<6) {
   return "Suficiente";
  }else if (valor>=6 && valor<7) {
   
   return "Bien";
  }else if (valor>=7 && valor<9) {
   
   return "Notable";
  }else return "SobreSaliente";
  
  
 }

Usando JUnit Parameterized Test

Vamos a construir una prueba unitaria que nos permite Testear cuando uno nota es MuyDefiente . Es decir se encuentra ubicada entre 0 y 3.

package com.arquitecturajava.models;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class NotaTest2 {
 
 

 @Test
 public void muyDeficienteTestSencillo() {
  
  Nota nota = new Nota("matematicas",2);
  String calificacion= nota.getCalificacion();
  assertEquals("MuyDeficiente",calificacion);
 }

 
}

Este test es funcional pero en muchos casos nos interesará validar también los limites de la Nota. En este caso que los valores sean 0 o 3. Añadimos más código al test

@Test
 public void muyDeficienteTestSencillo() {
  
  Nota nota = new Nota("matematicas",2);
  String calificacion= nota.getCalificacion();
  assertEquals("MuyDeficiente",calificacion);
  
  
  Nota nota2 = new Nota("matematicas",2);
  String calificacion2= nota2.getCalificacion();
  assertEquals("MuyDeficiente",calificacion2);
  
  
  
  Nota nota3 = new Nota("matematicas",2);
  String calificacion3= nota3.getCalificacion();
  assertEquals("MuyDeficiente",calificacion3);
 }

Test y Limitaciones

El Test nos es más práctico ya que valida los límites del valor . Sin embargo hay que escribir mucho más código para llegar a esa situación . En principio no nos puede parecer preocupante , pero cuando tengamos muchos Test será más código que leer. Podemos simplificar este código con un JUnit Parameterized Test que nos permite asociar a la prueba unitaria unos parámetros y pasárselos al método a través de una variable.

package com.arquitecturajava.models;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class NotaTest2 {
 
 
 
 @ParameterizedTest
 @DisplayName("Nota insuficiente valor:2 standar valor: 0,3 limites nota")
 @ValueSource (doubles= {2,0,3})
 public void muyDeficienteTest(double valorNota) {
  
  Nota nota2 = new Nota("matematicas",valorNota);
  String calificacion= nota2.getCalificacion();
  assertEquals("MuyDeficiente",calificacion);
  
 
 }
 


}

@ParameterizedTest

En este caso hemos usado la anotación @ParameterizedTest y @ValueSource para parametrizar el test y que reciba un parámetro con diversos valores.

Esto reduce el código de forma significativa y nos permite tener unas pruebas unitarias mucho más compactas.

Otros artículos relacionados