¿Qué es Mockito?
Mockito es un framework de pruebas unitarias que te permite crear objectos simulados (mocks) con una API limpia y simple haciendo que las pruebas sean legibles.
Vídeo Explicativo
Mockito dependencias
Configurar Mockito es bastante sencillo, solo necesitamos agregar la siguiente dependencia:
Maven
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.8.0</version>
<scope>test</scope>
</dependency>
Gradle
Groovy:
testImplementation 'org.mockito:mockito-core:4.8.0'
Kotlin:
testImplementation("org.mockito:mockito-core:4.8.0")
Activar Mockito
Antes de continuar, exploremos diferentes formas de habilitar el uso de anotaciones con las pruebas de Mockito.
MockitoJUnitRunner
La primera opción que tenemos es anotar la prueba JUnit con un MockitoJUnitRunner:
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
...
}
MockitoAnnotations.openMocks()
Alternativamente, podemos habilitar las anotaciones de Mockito mediante programación invocando MockitoAnnotations.openMocks():
@Before
public void init() {
MockitoAnnotations.openMocks(this);
}
Objectos Simulados (Mocks)
En la programación orientada a objetos , los objetos simulados son objetos simulados que imitan el comportamiento de los objetos reales de forma controlada.
Mockito.mock()
Podemos usar el método mock() de la clase Mockito para crear un objeto simulado de una clase o interfaz determinada. Esta es la forma más sencilla de simular un objeto.
@Test
public void test() {
List<String> mockList = Mockito.mock(List.class);
Mockito.when(mockList.size()).thenReturn(5);
assertTrue(mockList.size() == 5);
}
Anotación @Mock
También podemos simular un objeto usando la anotación @Mock. Es útil cuando queremos usar el objeto simulado en varios lugares porque evitamos llamar al método mock() varias veces. El código se vuelve más legible y podemos especificar un nombre de objeto simulado que será útil en caso de errores.
@Mock
List<String> mockList;
@Test
public void test() {
when(mockList.get(0)).thenReturn("Hola Mundo");
assertEquals("Hola Mundo", mockList.get(0));
}
Anotación @InjectMocks
Cuando queremos inyectar un objeto simulado (mock) en otro objeto simulado, podemos usar la anotación @InjectMocks. @InjectMock crea el objeto simulado de la clase e inyecta los objectos simulados que están marcados con la anotación @Mock en él.
class UsuarioServicioTest {
@Mock
UsuarioRepositorio usuarioRepositorio;
@InjectMocks
UsuarioServicio servicio;
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
}
@Test
public void test() {
UsuarioDto esperado = UsuarioDto(0, "Juan");
Mockito.when(usuarioRepositorio.obtenerUsuario(0)).thenReturn(UsuarioDto(0, "Juan"));
UsuarioDto resultado = servicio.obtenerUsuario(0);
Assertions.assertEquals(esperado, resultado);
}
}
class UsuarioServicio {
private UsuarioRepositorio usuarioRepositorio;
public void obtenerUsuario(long id) {
return usuarioRepositorio.obtenerUsuario(id);
}
}
Usando when().thenReturn() y when().thenThrow()
when().thenReturn()
Los objectos simulados (mocks) pueden devolver diferentes valores según los argumentos pasados a un método. La cadena de métodos when(….).thenReturn(….) se utiliza para especificar un valor de retorno para una llamada de método con parámetros predefinidos.
También puedes usar métodos como anyString() o anyInt() que se encuentran dentro de la clase ArgumentMatchers para definir que, según el tipo de entrada, se debe devolver un determinado valor.
Si especifica más de un valor, se devuelven en el orden de especificación, hasta que se utiliza el último. Posteriormente se devuelve el último valor especificado.
A continuación se muestra el uso de when(….).thenReturn(….).
@Test
void testeandoConWhenThenReturn() {
UsuarioDto esperado = UsuarioDto(0, "Juan");
// aqui simularemos que queremos que el método devuelva
Mockito.when(usuarioRepositorio.obtenerUsuario()).thenReturn(UsuarioDto(0, "Juan"));
UsuarioDto resultado = servicio.obtenerUsuario(0);
Assertions.assertEquals(esperado, resultado);
}
when().thenThrow()
Si por el contrario, nosotros quisieramos simular que al llamar al método, este nos devuelva una excepción en vez de un valor en concreto entonces deberemos de usar when(….).thenThrow(….).
@Test
void testeandoConWhenThenThrow() {
// aqui simularemos que queremos que el método devuelva una excepción
Mockito.when(usuarioRepositorio.obtenerUsuario(0)).thenThrow(new NoEncontradoException("Usuario no encontrado"));
Throwable exception = assertThrows(NoEncontradoException.class, () ->
servicio.obtenerUsuario(0));
assertEquals("Usuario no encontrado", exception.getMessage());
}