Test con parámetros en JUnit.
Haciendo pruebas unitarias siempre queremos que las mismas sean lo más fuertes posibles, con los tutoriales de JUnit assertions, assumptions y Hamcrest se pueden hacer, pero falta algo, hacer las pruebas con distintos parámetros y probar ese test con varios casos para asegurarnos de que en realidad el test funciona de manera correcta, para hacer pruebas unitarias parametrizadas en JUnit hay varias maneras, yo en este tutorial voy a poner los más usados y el que recomiendo.
Una prueba unitaria parametrizada no es más que un método de prueba en el cual deben realizarse como si de un bucle
Una prueba unitaria parametrizada no es más que un método de prueba en el cual deben realizarse como si de un bucle
for
se tratara una prueba por cada grupo de parámetros, esto hace la prueba unitaria mucho mas fuerte ya que así verificamos que en todos los casos posibles pase la prueba. Por ejemplo si no sabemos bien como hacer pruebas parametrizadas podemos utilizar nuestra lógica sencilla y hacer una prueba unitaria parecida a esta, lo cual no está mal pero hay una mejor manera:/** * Creamos la prueba unitaria con varios parametros de entrada * * @param num1 * @param num2 * @param resultadoEsperado */ @Test public void testMetodoSumar(int num1, int num2, int resultadoEsperado) { assertThat(resultadoEsperado, is(sumar(num1, num2))); } /** * Metodo en el cual ejecutamos la prueba unitaria n veces */ @Test public void testMetodoParametrizado() { // Creamos una lista de numeros enteros ListSi ejecutamos esa prueba unitaria pasa sin ningún problema y esto es lo que sale en la pantalla de JUnit:lista = new ArrayList<>(); // Agregamos ciertos numeros lista.add(2); lista.add(4); lista.add(6); // Por cada elemento en la lista ejecutamos la prueba unitaria for (int num : lista) { testMetodoSumar(num, num, (num + num)); } }
for
??... Bueno para ver qué sucede cambiamos un poco el código en la parte del bucle for
por algo como esto:
for (int num : lista) { testMetodoSumar(num, num, (num + num+1)); }Y ahora vemos la pantalla de JUnit y nos aparece esto:
for
no haya finalizado. Tampoco hay mucho detalle, así que esta manera de hacer pruebas unitarias parametrizadas no es la mejor ni la correcta.
Parametized
, la cual con simples anotaciones nos permite correr nuestros test fácilmente, para hacerlo vamos a crear una clase nueva llamada SumarTest
que obviamente se va encargar de hacerle la prueba unitaria a el método sumar(int a, int b)
, al crear la clase le ponemos la anotación @RunWith(Parameterized.class)
, creamos en este caso tres variables de tipo int
que representan los números a sumar y el resultado, un constructor de la clase y una lista en la cual pasamos los parámetros con los cuales vamos hacer la prueba unitaria, vamos a la práctica de una:
package datojavaTest; import static org.junit.Assert.assertThat; import java.util.ArrayList; import java.util.Collection; import org.hamcrest.CoreMatchers; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; /** * @author datojava.blogspot.com */ @RunWith(Parameterized.class) public class SumarTest extends CoreMatchers { private int num1; private int num2; private int resultado; public SumarTest(int x, int y, int z) { this.num1 = x; this.num2 = y; this.resultado = z; } @Parameters public static CollectionOk una vez listo voy a explicar un poco como funciona eso de los parámetros:init() throws Exception { Collection parametrosSuma = new ArrayList (); // Agregamos varios parametros, vamos a provocar la falla del test parametrosSuma.add(new Integer[] { 5, 2, 7 }); parametrosSuma.add(new Integer[] { 5, 4, 5 }); parametrosSuma.add(new Integer[] { 1, 5, 5 }); parametrosSuma.add(new Integer[] { 8, 1, 9 }); return parametrosSuma; } public int sumar(int num1, int num2) { return num1 + num2; } @Test public void test() { assertThat("ERROR en la suma: ", this.resultado, is(sumar(this.num1, this.num2))); } }
@Parameters public static CollectionVemos que la lista tiene por cada ítem uninit() throws Exception { Collection parametrosSuma = new ArrayList (); // Agregamos varios parametros, vamos a provocar la falla del test parametrosSuma.add(new Integer[] { 5, 2, 7 }); parametrosSuma.add(new Integer[] { 5, 4, 5 }); parametrosSuma.add(new Integer[] { 1, 5, 5 }); parametrosSuma.add(new Integer[] { 8, 1, 9 }); return parametrosSuma; }
Array
de tipo de datos Integer
el cual tiene tres enteros, por cada arreglo esta es la representación:new Integer[] { 5, 2, 7 }
Primer entero es = num1
Segundo entero es = num2
Tercer entero es = resultado
Esto es lo que estamos representado como operación (num1 + num2 = resultado)
Esta justo en este orden por que en el constructor lo estamos haciendo de esa manera:
public SumarTest(int x, int y, int z) { this.num1 = x; this.num2 = y; this.resultado = z; }
Como vemos el constructor recibe tres parámetros
int
con las cuales inicializamos las variables num1
, num2
y resultado
, por ejemplo si digo que num1 = z
ya todo cambia porque estamos pasando lo que nosotros estamos diciendo que es el resultado a la variable num1
. De este constructor dependen todas los parámetros que vamos a utilizar para la prueba unitaria.Bueno una vez aclarado el tema de cómo funciona a nivel de código podemos pasar a la práctica, si analizamos el código vemos que falla en la segunda y tercera ronda de prueba porque estamos diciendo que:
(5 + 4 = 5) Falso
(1 + 5 = 5) Falso
Provocamos el error para ver cómo funciona en comparación con el primer ejemplo, esto es lo que sucede:
Parametized
, esta clase tiene ciertas limitaciones, solo puedes crear un constructor de la clase porque si no lanza la excepción java.lang.IllegalArgumentException: Test class can only have one constructor, eso quiere decir que todas las pruebas unitarias van a correr con los mismos parámetros, ósea que para hacer pruebas parametrizadas con la clase Parametized
tendrás que crear una clase para cada prueba unitaria que quieras correr con distintos parámetros, una cag... Ahora te presento otra manera de hacer tus test parametrizados en JUnit con la librería
JUnitParams-1.0.2
, puedes descargar el .jar aquí, una vez descargado lo incorporas al build path de tu proyecto, esta librería nos permite hacer lo que hemos planteado anteriormente y de una manera mas fácil, en una clase podemos hacer varios test con parámetros diferentes sin necesidad de crear variables y constructores. También trabaja con anotaciones, la clase en donde vamos a implementar las pruebas unitarias tenemos que agregarle esta anotacion @RunWith(JUnitParamsRunner.class)
, y para utilizar los parámetros solo tenemos que agregar la anotación @Parameters
con los respectivos parámetros. Vamos a la práctica de una:
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import java.util.ArrayList; import java.util.Collection; import junitparams.JUnitParamsRunner; import junitparams.Parameters; import org.hamcrest.CoreMatchers; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(JUnitParamsRunner.class) public class DatoJavaJUnitParams extends CoreMatchers { public CollectionSi analizamos el código del ejemplo anterior vemos que podemos hacer varias pruebas unitarias con distintos parámetros y de distintas formas, la prueba unitarialistaInt() { Collection datos = new ArrayList (); datos.add(new Integer[] { 5, 2, 7 }); datos.add(new Integer[] { 5, 4, 9 }); datos.add(new Integer[] { 1, 5, 6 }); datos.add(new Integer[] { 8, 1, 9 }); return datos; } public int sumar(int num1, int num2) { return num1 + num2; } @Test @Parameters({ "1, 3, 4", "5, 5, 10", "6, 8, 14", "98, 1, 99" }) public void testSuma(int x, int y, int e) { assertThat("ERROR, no es el resultado esperado", e, is(sumar(x, y))); } @Test @Parameters({ "16, 15, 31", "52, 6, 55", "45, 48, 93", "12, 65, 67", "27, 63, 90" }) public void testSuma1(int x, int y, int e) { assertEquals("ERROR, no es el resultado esperado", e, sumar(x, y)); } @Test @Parameters(method= "listaInt") public void testSuma2(int x, int y, int e) { assertEquals("ERROR, no es el resultado esperado", e, sumar(x, y)); } }
testSuma2(int x, int y, int e)
es distinta a las demás, de hecho al principio del codigo hemos creado un método que se llama listaInt()
en el que llenamos una lista con distintos parámetros, ese método lo utilizamos como parámetros de prueba con la anotación @Parameters(method= "listaInt")
, Algo que es bastante util a la hora de hacer pruebas unitarias con los mismo parámetros. Esta es la salida en JUnit de esta clase:
JUnitParams
. Pon en práctica lo aprendido y si tienes alguna duda o comentario no te olvides de decírmelo por aquí...
No hay comentarios :
Publicar un comentario