jueves, 22 de marzo de 2018

Un poquito de Mockito

Ya llevo tiempo queriendo hacer algo con Mockito y en este post vamos a explicar un poco que es y como usarlo.

Mockito es una librería muy famosa que nos permitirá 'mockear' es decir 'engañar' en las pruebas, para hacer que un objeto simule un determinado comportamiento. De esta forma podremos probar ciertas funcionalidades más facilmente, sin necesidad de tener configurado o disponibles todos los actores de la prueba. 

Con la clausula 'when' y 'thenReturn' podemos hacer que un objeto del cual no tengamos una implementación se comporte como queramos. Esto puede necesario si por ejemplo obtenemos los datos de la BBDD y aún no se haya desarrollado el DAO.

Book mockBook = mock(Book.class);
when(mockBook.getName()).thenReturn("Ender's Game");
assertThat("Ender's Game", equalTo(mockBook.getName()));

Podemos simular el comportamiento para cuando debe lanzar una excepción a través del método 'thenThrow'. En este ejemplo también veremos que aparte de los métodos propios de la clase 'Mockito', tambien existen los 'ArgumentMatchers'. Los cuales nos permiten indicarle aa mockito que puede aceptar un rango de valores y permitiendo así hacer una prueba más genérica.

@Test(expected = ArithmeticException.class)
public void throwMethod() {
 Calculator mockCal = mock(Calculator.class);
 when(mockCal.divide(anyInt(), eq(0))).thenThrow(ArithmeticException.class);
 mockCal.divide(1, 0);
}

Podemos reducir un poco el código haciendo uso de anotaciones para 'mockear' los objetos, pero será neceario indicar que se ejecuta la clase con 'MockitoJUnitRunner' o iniciar los objetos explicitamente.  También podemos hacer uso de métodos estaticos similares a los anteriores como es 'doReturn' y así replicar el comportamiento de otra forma.

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
 @Mock
 Book book;
 @Test
 public void doReturnMethod() {
  doReturn("Ender's Game").when(book).getName();
  assertThat("Ender's Game", equalTo(book.getName()));
 }
}

También esta el método 'spy' que permite hacer un wrapper de un objeto existente. Este objeto se comportará como el original a menos que 'mockeemos' algún método.

@Test
public void spy() {
 Book book = new Book();
 book.setAuthor("Orson Scott Card");
 Book spyBook = spy(book);
 when(spyBook.getName()).thenReturn("Ender's Game");
 assertThat("Orson Scott Card", equalTo(spyBook.getAuthor()));
 assertThat("Ender's Game", equalTo(spyBook.getName()));
}

Disponemos del método 'verify' que nos permite 'verificar' las llamadas que se han hecho a nuestro objeto 'mockeado'. Y junto a este método podemos usar un objeto de tipo 'captor' que nos permite obtener información sobre los argumentos/parámetros que se usan en las llamadas 'mockeadas'.

@Mock
private Book bookMock;
@Captor
private ArgumentCaptor<String> captor;
@Test
public void verifyAndCaptorMethod() {
 bookMock.setName("Ender's Game");
 verify(bookMock).setName(ArgumentMatchers.eq("Ender's Game"));
 verify(bookMock, times(1)).setName("Ender's Game");
 verify(bookMock).setName(captor.capture());
 assertThat("Ender's Game", equalTo(captor.getValue()));
}

Por último, al menos en este post, hablaremos de la anotación 'InjectMocks' que nos permitirá crear un objeto cuyos argumentos del constructor son mocks ya configurados.

@Mock
private Book bookMock;
@InjectMocks
private Library library; // constructor -> public Library(final Book book) 
@Test
public void injectMethod() {
 when(bookMock.getName()).thenReturn("Ender's Game");
 assertThat("Ender's Game", equalTo(library.getList().get(0).getName()));
}

No hay comentarios:

Publicar un comentario