JUnit y Mockito — Comenzando mis primeros test

JUnit

Es un framework open source que permite realizar pruebas unitarias y de integración sobre sistemas en JAVA. Este framework disponibiliza herramientas, clases y métodos que simplifican la elaboración de las pruebas de sistemas.

Algunos términos clave:

Métodos

  • setUp: Permite asignar valores iniciales a las variables antes de iniciar cada test.

  • tearDown: Es llamada despues de cada test, usada para liberar recursos.

  • test: Las pruebas a realizar

Tambien se considera que pueden existir otros métodos para ser un usadas por las pruebas

Anotaciones

  • @RunWith: Se le asigna una clase a la que JUnit invocará en lugar del ejecutor por defecto de JUnit

  • @Before: Indicamos que el siguiente método se debe ejecutar antes de cada test (precede al método setUp). Si tiene que preceder al método setUpClass, la notación será “@BeforeClass

  • @After: Indicamos que el siguiente método se debe ejecutar después de cada test (precede al método tearDown). Si tiene que preceder al método tearDownClass, la notación será “@AfterClass

  • @Test: Indicamos a Junit que se trata de un método de Test. En versiones anteriores de JUnit los métodos tenían que tener un nombre con la siguiente estructura: “Test”. Con esta notación colocada delante de los métodos podemos elegir el nombre libremente.

Listado completo de anotaciones: JUnit — Anotaciones

Funciones de aceptación/rechazo

  • sertArrayEquals: Recibe como parámetro dos arrays y comprueba si son iguales. Devuelve assertionError si no se produce el resultado esperado

  • sertEquals: Realiza la comprobación entre dos valores de tipo numérico. Devuelve assertionError si no se produce el resultado esperado

  • sertTrue: Comprueba si una condición se cumple. Devuelve assertionError si no se produce el resultado esperado

  • il: devuelve una alerta informando del fallo en el test

Ejemplo

Mockito

Mockito es una librería Java que permite simular el comportamiento de una clase de forma dinámica. De esta forma nos aislamos de las dependencias con otras clases y sólo testeamos la funcionalidad concreta que queremos.

El ejemplo clásico de un objeto mock es un proveedor de datos, cuando se ejecuta la aplicación el componente se conectará a una base de datos y proveerá datos reales, pero cuando se ejecuta un test unitario lo que buscamos es aislarlo y para esto necesitamos un objeto mock que simulará la fuente de datos, esto asegurará que las condiciones de prueba sean siempre las mismas.

La simulación del comportamiento de una clase se hace mediante los “dobles” que pueden ser de distintos tipos:

  • Dummy: Son objetos que se utilizan para realizar llamadas a otros métodos, pero no se usan.

  • Stub: es como un dummy ya que sus métodos no hacen nada, pero devuelven cierto valor que necesitamos para ejecutar nuestro test con respecto a ciertas condiciones.

  • Spy: Es un objeto real que permite verificar el uso que se hace del propio objeto, por ejemplo el número de veces que se ejecuta un método o los argumentos que se le pasan.

  • Mock: Es un stub en el que sus métodos sí implementan un comportamiento, pues esperan recibir unos valores y en función de ellos devuelve una respuesta.

  • Fake: Son objetos que tienen una implementación que funciona pero que no son apropiados para usar en producción (por ejemplo, una implementación de HttpSession).

Ejemplos usando mockito

Ejemplo 1: Verificar comportamiento

//creacion de mock
List mockedList = mock(List.class);//utilizando el mock objectmockedList.add("one");
mockedList.clear();//verificacion
verify(mockedList).add("one");
verify(mockedList).clear();

Ejemplo 2: Stubbing

También podemos programar el comportamiento de los mocks, indicando qué
deben devolver ciertos métodos.

//se pueden hacer mock de clases concretas, no solo interfaces
LinkedList mockedList = mock(LinkedList.class);//stubbing
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());//imprime "first"
System.out.println(mockedList.get(0));//lanza runtime exception
System.out.println(mockedList.get(1));//imprime "null" porque no se ha hecho stubbing de get(999)
System.out.println(mockedList.get(999));verify(mockedList).get(0);

Por defecto todos los métodos que devuelven valores de un mock devuelven
null, una colección vacía o el tipo de dato primitivo apropiado.

Ejemplo 3: Argument matchers

Los arguments matchers permiten realizar llamadas a métodos mediante
‘comodines’, de forma que los párametros a los mismos no se tengan que definir explícitamente:

//stubbing usando anyInt() argument matcher
when(mockedList.get(anyInt())).thenReturn("element");//stubbing usando hamcrest (libreria de matchers) (digamos que isValid() devuelve tu propio matcher):
when(mockedList.contains(argThat(isValid()))).thenReturn("element");//imprime "element"
System.out.println(mockedList.get(999));//tambien se puede verificar usando argument matchers
verify(mockedList).get(anyInt());

Argument matchers permiten realizar stubbing o verificaciones muy flexibles.
podéis ver mas en http://mockito.googlecode.com/svn/branches/1.7/javadoc/org/mockito/Matchers.html

Ejemplo 4: Verficiando el numero exacto de invocaciones, al menos X, o ninguna invocación

Vamos a ver ahora cómo verificar si se ha un cumplido un número mínimo o
máximo de llamadas al mock:

//usando mock
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");//las dos verificaciones siguientes trabajan de la misma manera (times(1) se usa por defecto)
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once");//verificacion de numero exacto de invaciones
verify(mockedList, times(2)).add("twice");
verify(mockedList, times(3)).add("three times");//verificacion utilizando never. never() es un alias de times(0)
verify(mockedList, never()).add("never happened");//verificacion utilizando atLeast()/atMost()
verify(mockedList, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("five times");
verify(mockedList, atMost(5)).add("three times");

Ejemplo 5: Verificaciones en orden

Si necesitamos que varios mock necesiten llevar un orden específico en las
llamadas lo podemos realizar de la siguiente manera:

List firstMock = mock(List.class);
List secondMock = mock(List.class);

//usando mocks
firstMock.add("was called first");
secondMock.add("was called second");

//creamos un objeto inOrder, pasando los mocks que necesitan verificarse en orden
InOrder inOrder = inOrder(firstMock, secondMock);

//verficamos que firstMock ha sido invocado antes que secondMock
inOrder.verify(firstMock).add("was called first");
inOrder.verify(secondMock).add("was called second");

Realizar verificaciones en orden son muy flexibles. no es necesario
verificar todas las interacciones, si no sólo aquellas que necesitamos.

Ejemplo 6: Asegurandonos que alguna(s) interaccion(es) nunca ocurren en un mock

//usando mocks - solo se interactua sobre mockOne
mockOne.add("one");

//verificacion ordinaria
verify(mockOne).add("one");

//verificamos que el metodo nunca ha sido llamado en el mock
verify(mockOne, never()).add("two");

//verificamos que otros mocks no obtienen interactuaciones
verifyZeroInteractions(mockTwo, mockThree);

Ejemplo 7: @Mock

Nos permite realizar mocks anotando el código, y así el mismo queda más
claro y limpio.

public class ArticleManagerTest { 

       @Mock private ArticleCalculator calculator;
       @Mock private ArticleDatabase database;
       @Mock private UserProvider userProvider;

       private ArticleManager manager;
       ...
}

Importante! La siguiente llamada debe encontrarse en algun lugar de una
clase base o del test runner:

MockitoAnnotations.initMocks(testClass);

JUnit Vs Mockito

JUnit es un marco que ayuda a escribir y ejecutar sus pruebas unitarias y Mockito (o cualquier otra herramienta de burla) es un marco que utiliza específicamente para escribir de manera eficiente cierto tipo de pruebas.

Un aspecto central en las pruebas unitarias es el hecho de que desea aislar su “clase bajo prueba” de cualquier otra cosa en el mundo. Para hacerlo, a menudo tiene que crear “dobles de prueba” que proporcione a un objeto de su “clase bajo prueba”. Puede crear todos esos “dobles de prueba” manualmente; o usas un marco burlón que genera objeto de una clase determinada para ti usando técnicas de reflexión. Curiosamente, algunas personas abogan por nunca usar marcos burlones; pero sinceramente: no me puedo imaginar haciendo eso.

En otras palabras: definitivamente puedes usar JUnit sin usar un marco burlón. Lo mismo es cierto para la dirección inversa; pero en realidad, no hay muchas buenas razones por las que desearía usar Mockito para otra cosa que no sea la prueba de unidad.

Referencias:

0
Subscribe to my newsletter

Read articles from Juan Pablo Saldivar Rojas directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Juan Pablo Saldivar Rojas
Juan Pablo Saldivar Rojas

Engineering manager in Buk, Software architect with AWS and GCP skills, devops enthusiast. Senior developer in JS and Java. I love the ocean and all its life. I'm an underwater diver, vegan and beginning underwater photographer.