Tests parametrizados con JUnit 5

Las pruebas son imprescindibles para el desarrollo de cualquier aplicación, herramienta o sistema, ya que garantizan que el software funciona como debe, nos ayudan a encontrar errores o defectos que aún no se han detectado y reducen los costes.

Un buen sistema de pruebas contempla todos los posibles escenarios que se han implementado en el diseño con el objetivo de validar el correcto funcionamiento del software.

Actualmente existen en el mercado múltiples herramientas que nos facilitan el proceso, la más utilizada para desarrollos en Java es JUnit.

¿Qué es y para qué sirve JUnit?

Es el framework de testing para aplicaciones Java más utilizado. Aunque fue diseñado para la automatización de las pruebas unitarias, también se puede emplear para pruebas de integración, end-to-end, aceptación o incluso para controlar las pruebas regresión dado que optimiza el proceso.

JUnit 5 también conocido como JUnit Jupiter es la última versión y nos proporciona una serie de características que nos permite simplificar la realización de pruebas unitarias. En este post nos centraremos en los tests parametrizados, una de las más avanzadas e interesantes.

¿Qué son los tests parametrizados?

Los tests parametrizados son unos tests unitarios en donde uno o varios valores son inyectados a uno o varios parámetros con el fin de evitar la duplicación del código. Se trata de un concepto que ya estaba presente en JUnit 4 pero que en JUnit 5 se mejora aprovechando lo mejor de la versión anterior.

¿Por qué parametrizar nuestros tests?

Muchas veces cuando testeamos un método que implementa una determinada lógica en base a una o varias condiciones creamos varios tests para probar cada uno de los posibles escenarios con el fin de obtener la mayor cobertura posible. Sin embargo, esta no siempre es la mejor estrategia, ya que al final terminamos creando innecesariamente varios tests que se podrían reducir a uno mediante su parametrización.

Veamos un ejemplo:

Tenemos este método en nuestra clase y queremos probarlo

Alba Batista Santos
Alba Batista SantosDesarrolladora JAVA en VIEWNEXT

Para obtener la máxima cobertura creamos estos 3 tests: uno para cuando el carácter tiene datos, en este caso un “a”, otro para cuando es vacío y por último cuando éste es nulo.

No obstante, podríamos reducir estos tests a uno solo parametrizando el argumento carácter que es el que cambia en cada uno de los tests anteriores:

Como podemos observar, este test se ejecuta 3 veces, una por cada valor inyectado al parámetro, siguiendo el orden en el que se han declarado las anotaciones

Si ahora comprobamos la cobertura con el plugin de Jacoco podemos ver que seguimos teniéndola al 100%

Ventajas

  • Simplifican los tests unitarios
  • Reduce la duplicación de código
  • Aumenta la cobertura
  • Escalabilidad: Es fácil añadir más escenarios

Configuración

Para poder crear tests parametrizados tendremos que cumplir algunos requisitos:

  • Que nuestro proyecto tenga la versión 8 de Java o superior: Dado que JUnit 5 se apoya de algunas de las novedades que se introdujeron a partir de esta versión como son las expresiones lambdas.
  • Crear un test case del tipo JUnit Jupiter (JUnit 5)

  • Tener la dependencia junit-jupiter-params en nuestro proyecto. En el caso de Spring Boot, esta dependencia ya viene incluida en el spring-boot-starter-test.

Maven:

 

Gradle:

dependencies {

testCompile(«org.junit.jupiter:junit-jupiter-

params: 5.10.2»)

}

Anotaciones

Para crear un test parametrizado lo primero que tenemos que hacer es utilizar la anotación @ParameterizedTest que sustituye a la anotación @Test.

No obstante, esto no es suficiente puesto que tendremos que especificar al menos otra anotación, que dependiendo del tipo de valor que queramos inyectar a nuestro parámetro usaremos una u otra o incluso las combinaremos. A continuación, repasaremos las anotaciones que más nos puedan ser de utilidad:

ValueSource

  • @ValueSource: Inyecta un array de literales que puede ser de tipo; String, char, int, long, double, short, byte, float, boolean o Class<?>.

EmptySource

  • @EmptySource: Inyecta una cadena vacía

NullSource

  • @NullSource: Inyecta un null.

NullAndEmptySource

  • @NullAndEmptySource: Es la combinación de las anotaciones @NullSource y @EmptySource.

Nos puede resultar muy útil emplearla en aquellos casos tanto si necesitamos comprobar que una variable sea nula o vacía.

Cabe resaltar que en las anotaciones anteriores solo nos permiten parametrizar un solo argumento, en caso de que queramos parametrizar más de uno tendremos que recurrir a la siguiente anotación:

MethodSource

  • @MethodSource: Inyecta los valores que devuelve el método factory referenciado

Como podemos observar en el ejemplo probamos un método que calcula la diferencia en días entre dos fechas, para ello creamos un método factory “provideArgumentsForCalcularDiasEntreFechasTest” donde especificamos los valores de cada uno de los argumentos y después lo referenciamos indicando el nombre del método.

Un detalle a considerar es que, si nos fijamos bien, vemos que en el método factory declaramos las fechas como String, mientras que en el método que testeamos éstas son de tipo LocalDate. Esto es porque JUnit 5 realiza de manera implícita la conversión, siendo capaz de convertir objetos que han sido declarados como String a otros tipos como int, double, boolean, char … etc, incluso para las clases.

EnumSource

  • @EnumSource: Inyecta las constantes de la enumeración pasada como argumento. Además, nos permite excluir o ejecutar solamente aquellos valores que nos interesen.

En este ejemplo testeamos la enumeración DayOfWeek, dicha enumeración representa los días de la semana, los cuales van a asociados a un número, en este caso comprobamos que el número de día esté situado entre 1 y 7.

CSVSource

  • @CsvSource: Inyecta uno o varios arrays de valores separados por comas que representan las líneas de un fichero csv

En este ejemplo utilizamos 2 propiedades:

  • Delimiter: Recibe un char que es el separador, por defecto es una coma.
  • Value: Recibe un array de strings, en donde cada array representa una línea de un fichero csv

CSVFileSource

  • @CsvFileSource: Funciona igual que la anotación anterior, pero con la diferencia de que, en vez de pasar directamente el array, éste lee el fichero csv de la ruta especificada en la propiedad resources.

Conclusión

En definitiva, los tests parametrizados son una característica poderosa de JUnit que nos permite crear de una manera muy sencilla unos tests capaces de cubrir todos los posibles escenarios aumentando la cobertura y reduciendo la duplicación de código. De esta forma tenemos unos tests más compactos y completos.

Os animo a implementarlo en vuestros proyectos por todas las ventajas que ofrece y por su facilidad.

Otros artículos relacionados

2024-03-20T14:34:11+01:0020 marzo, 2024|

¡Compártelo en tus redes sociales!

Ir a Arriba