En el artículo anterior, estuvimos viendo cómo establecer un test de la clase de validación que escribimos. Con lo explicado, no hay duda que podemos realizar las pruebas necesarias, pero, cuando el proyecto es grande, o, somos suficientemente responsables como para escribir una casuística de test larga, hay formas mas agradables de escribir esos test
En este articulo, veremos algunas formas de mejorar la claridad de nuestros test. utilizando los test parametrizados y, entregando valores desde array, listas, ficheros y métodos
Los ParameterizedTest
Hasta ahora, hemos visto como hacer múltiples pruebas en una rutina, y, aunque hemos conseguido que corriesen todas, aunque alguna diera error, también es cierto que, descubrir cual era la que fallaba era un poco «delicado».
Me acuerdo también, de haber comentado que la mejor forma de encarar varios test, es escribir un método para cada uno de ellos, aunque esa metodología hace que nuestros test pueda ser inmenso.
La solucion esta en utilizar la anotación de @ParameterizedTest, y luego indicar los distintos valores sobre el que queremos realizar el test.
Tambien tenemos alguna anotación para reducir el numero de lineas a escribir
- @NullSource – Nos envia a la entrada el valor nulo
- @EmptySource – Nos envia a entrada una cadena vacia
- @NullAndEmptySource – Nos envía a la entrada una cadena nula, y despues una vacía
- @ValueSource – Nos envía a la entrada el valor que indiquemos a continuación. Si sigue un array, el test se llama cuantas veces haga falta, indicando en cada caso un valor
Sabiendo esto, nuestro primer test, en esta ocasion quedaria como
@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = { "\t", "\n" })
void testIsVacioLlegaNuloVacio(String entrada) {
if (entrada == null)
assertTrue(Rutinas.isVacio(entrada));
else
assertTrue(Rutinas.isVacio(entrada.trim()));
}
@ParameterizedTest
@ValueSource(strings = { "Hola\t", "h\n","Esto es una cadena ....." })
void testIsVacioLleganDatos(String entrada) {
assertFalse(Rutinas.isVacio(entrada.trim()));
}
En este caso, el test puede que tenga mas lineas, parte debido a un tratamiento obligatorio para el caso «null», y otro porque tengo que separar los test por positivo y por negativo, y esto ultimo, lo voy a tener que hacer casi siempre….
En el caso anterior, añadí los valores en la rutina; pero sabéis que me gusta centralizar las constantes al principio del modulo, por lo que tambien puedo combinar esas constantes con los nuevos sistemas; por ejemplo, puedo hacer
@ParameterizedTest
@ValueSource(strings = {CORREO_ELECTRONICO_CORRECTO,
CORREO_ELECTRONICO_CORRECTO_1,
CORREO_ELECTRONICO_CORRECTO_2
})
void testIsEmailValidoOK(String entrada) {
assertTrue(Rutinas.isEmailValido(entrada));
}
@ParameterizedTest
@ValueSource(strings = {CORREO_ELECTRONICO_ERRONEO_SIN_A,
CORREO_ELECTRONICO_ERRONEO_SIN_TLD,
CORREO_ELECTRONICO_ERRONEO_SIN_NOMBRE,
CORREO_ELECTRONICO_ERRONEO_SIN_DOMINIO,
CORREO_ELECTRONICO_ERRONEO_CON_NUM
})
void testIsEmailValidoNOK(String entrada) {
assertFalse(Rutinas.isEmailValido(entrada));
}
Naturalmente, siempre que arriba haya definido las constantes como
//*******Pruebas de validacion de Correo Electronico**************
final String CORREO_ELECTRONICO_CORRECTO = "[email protected]";
final String CORREO_ELECTRONICO_CORRECTO_1 = "[email protected]";
final String CORREO_ELECTRONICO_CORRECTO_2 = "[email protected]";
final String CORREO_ELECTRONICO_ERRONEO_SIN_A = "migarcia.recursosformacion.com";
final String CORREO_ELECTRONICO_ERRONEO_SIN_TLD = "migarcia@recursosformacion";
final String CORREO_ELECTRONICO_ERRONEO_SIN_NOMBRE = "@recursosformacion.com";
final String CORREO_ELECTRONICO_ERRONEO_SIN_DOMINIO = "migarcia@";
final String CORREO_ELECTRONICO_ERRONEO_CON_NUM = "[email protected]";
Utilización de @CsvSource
Estas soluciones, estan muy bien cuando solo requerimos un parametro para realizar el test, pero , en ocasiones, necesitamos mas de uno, por ejemplo, en los casos de nuevoSiNoVacio, necesitamos el valor actual del campo, el valor que queremos colocar, y, el resultado que debe devolver
Si no voy a parametrizar, la solucion puede ser
@Test
void testNuevoSiNoVacioLongLong() {
Long a = null;
Long c = 10L;
Long res = 7L;
assertAll(() -> assertEquals(Rutinas.nuevoSiNoVacio(res, a), 7L),
() -> assertEquals(Rutinas.nuevoSiNoVacio(res, c), 10L));
}
Pero si queremos parametrizarlo, debemos pasar al metodo los tres valores, que en ese ejemplo he construido dentro.
En este caso, si vamos a realizar varias pruebas, podemos parametrizarlo, y facilitar los datos por medio de un @CsvSource, o, incluso, leerlos de un fichero, indicandolo con @CsvFileSource
La unica limitacion que tiene, es que no puedo utilizar constantes definidas en cabecera, y tengo que indicarle los parametros aqui mismo; por ejemplo:
@ParameterizedTest
@CsvSource (value = {
"10,,10",
"7,25,25"
})
void testNuevoSiNoVacioLongLong1(Long tengo,Long llega,Long resultado) {
assertEquals(Rutinas.nuevoSiNoVacio(tengo, llega), resultado);
}
En el ejemplo, hago la prueba tambien con NULL, ya que recibo Long, si fuera con primitivos, no podria haber realizado la prueba de null
Trabajando con @MethodSource
Como caso final a esta introducción, os presento otra forma de parametrizar los test, y, es facilitando los datos desde un método.
Quizás, la idea no sea muy intuitiva, pero puede llegar a ser muy util. En nuestro ejemplo, lo he utilizado para el test de comparar fecha, ya que necesito inyectar LocalDate al método, y no es demasiado simple la conversión
Aqui teneis el ejemplo:
private static Stream<? extends Arguments> testDeFechas() {
List<String[]> list = new ArrayList<String[]>();
return Stream.of(
Arguments.of(List.of(AHORA,AHORA,0)),
Arguments.of(List.of(AHORA,MANIANA,-1)),
Arguments.of(List.of(MANIANA,AHORA,1)),
Arguments.of(List.of(MANIANA,AYER,3))
);
}
@ParameterizedTest
@MethodSource("testDeFechas")
void testComparaFechas2(List variables) {
LocalDate fecha = (LocalDate)variables.get(0);
LocalDate referencia = (LocalDate)variables.get(1);
assertEquals(Rutinas.comparaFechas(fecha,referencia), variables.get(2));
}
Conclusión
Este articulo es parte de Visión de conjunto con Spring y continuación del inicio del test, y teneis un desarrollo con más detalle en youTube, y, aunque es conveniente que intentéis escribirlo TODO vosotros, si queréis renunciar a ello, lo teneis tambien en GitHub
La explicación en YouTube:
Relacionado
Descubre más desde Recursos para formacion
Suscríbete y recibe las últimas entradas en tu correo electrónico.