fbpx

PRUEBAS UNITARIAS con MOCKITO en JAVA

¿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());
    }