En este tema, aprenderemos cómo integrar Mockito con JUnit para crear pruebas unitarias más efectivas y robustas. Mockito es una biblioteca de Java que permite crear objetos simulados (mocks) para pruebas unitarias. Esto es especialmente útil cuando queremos aislar el código que estamos probando de sus dependencias.
Contenido
- ¿Qué es Mockito?
- Configuración de Mockito con JUnit
- Creando Mocks con Mockito
- Inyectando Mocks en el Código
- Verificando Interacciones
- Ejemplo Práctico
- Ejercicios Prácticos
- ¿Qué es Mockito?
Mockito es una biblioteca de Java que permite crear objetos simulados (mocks) para pruebas unitarias. Los mocks son objetos que imitan el comportamiento de objetos reales en un entorno controlado. Esto es útil para probar el comportamiento de una clase sin depender de sus dependencias externas.
- Configuración de Mockito con JUnit
Para usar Mockito con JUnit, primero necesitamos agregar las dependencias necesarias a nuestro proyecto. Si estás usando Maven, agrega las siguientes dependencias a tu archivo pom.xml:
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.2</version>
<scope>test</scope>
</dependency>
</dependencies>Si estás usando Gradle, agrega las siguientes líneas a tu archivo build.gradle:
dependencies {
testImplementation 'org.mockito:mockito-core:3.11.2'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.7.2'
}
- Creando Mocks con Mockito
Para crear un mock con Mockito, usamos el método Mockito.mock(). Aquí hay un ejemplo básico:
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MyServiceTest {
@Test
public void testMyService() {
// Crear un mock de la clase Dependency
Dependency dependencyMock = Mockito.mock(Dependency.class);
// Definir el comportamiento del mock
Mockito.when(dependencyMock.someMethod()).thenReturn("Mocked Response");
// Usar el mock en la clase que estamos probando
MyService myService = new MyService(dependencyMock);
String result = myService.performAction();
// Verificar el resultado
assertEquals("Mocked Response", result);
}
}
- Inyectando Mocks en el Código
En lugar de crear manualmente los mocks, podemos usar anotaciones para simplificar el proceso. Mockito proporciona la anotación @Mock para crear mocks y @InjectMocks para inyectarlos en la clase que estamos probando.
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
public class MyServiceTest {
@Mock
private Dependency dependencyMock;
@InjectMocks
private MyService myService;
@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
public void testMyService() {
// Definir el comportamiento del mock
when(dependencyMock.someMethod()).thenReturn("Mocked Response");
// Usar el mock en la clase que estamos probando
String result = myService.performAction();
// Verificar el resultado
assertEquals("Mocked Response", result);
}
}
- Verificando Interacciones
Además de definir el comportamiento de los mocks, también podemos verificar que ciertos métodos fueron llamados con los argumentos correctos. Esto se hace usando el método Mockito.verify().
import static org.mockito.Mockito.verify;
@Test
public void testMyService() {
// Definir el comportamiento del mock
when(dependencyMock.someMethod()).thenReturn("Mocked Response");
// Usar el mock en la clase que estamos probando
String result = myService.performAction();
// Verificar el resultado
assertEquals("Mocked Response", result);
// Verificar que el método someMethod() fue llamado una vez
verify(dependencyMock).someMethod();
}
- Ejemplo Práctico
Vamos a ver un ejemplo más completo que incluye la creación de mocks, la inyección de dependencias y la verificación de interacciones.
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class UserServiceTest {
@Mock
private UserRepository userRepositoryMock;
@InjectMocks
private UserService userService;
@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
public void testGetUser() {
// Definir el comportamiento del mock
User mockUser = new User("John", "Doe");
when(userRepositoryMock.findUserById(1)).thenReturn(mockUser);
// Usar el mock en la clase que estamos probando
User result = userService.getUser(1);
// Verificar el resultado
assertEquals("John", result.getFirstName());
assertEquals("Doe", result.getLastName());
// Verificar que el método findUserById() fue llamado una vez con el argumento 1
verify(userRepositoryMock).findUserById(1);
}
}
- Ejercicios Prácticos
Ejercicio 1: Crear y Usar Mocks
- Crea una clase
Calculatorcon un métodoadd(int a, int b)que devuelve la suma deayb. - Crea una clase
CalculatorServiceque tenga una dependencia deCalculator. - Escribe una prueba unitaria para
CalculatorServiceusando Mockito para simular el comportamiento deCalculator.
Ejercicio 2: Verificar Interacciones
- Modifica la clase
CalculatorServicepara que tenga un métodocalculateSum(int a, int b)que use el métodoadddeCalculator. - Escribe una prueba unitaria para
calculateSumque verifique que el métodoadddeCalculatorfue llamado con los argumentos correctos.
Soluciones
Solución Ejercicio 1
// Calculator.java
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
// CalculatorService.java
public class CalculatorService {
private Calculator calculator;
public CalculatorService(Calculator calculator) {
this.calculator = calculator;
}
public int calculateSum(int a, int b) {
return calculator.add(a, b);
}
}
// CalculatorServiceTest.java
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
public class CalculatorServiceTest {
@Mock
private Calculator calculatorMock;
@InjectMocks
private CalculatorService calculatorService;
@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
public void testCalculateSum() {
// Definir el comportamiento del mock
when(calculatorMock.add(2, 3)).thenReturn(5);
// Usar el mock en la clase que estamos probando
int result = calculatorService.calculateSum(2, 3);
// Verificar el resultado
assertEquals(5, result);
}
}Solución Ejercicio 2
import static org.mockito.Mockito.verify;
@Test
public void testCalculateSum() {
// Definir el comportamiento del mock
when(calculatorMock.add(2, 3)).thenReturn(5);
// Usar el mock en la clase que estamos probando
int result = calculatorService.calculateSum(2, 3);
// Verificar el resultado
assertEquals(5, result);
// Verificar que el método add() fue llamado una vez con los argumentos 2 y 3
verify(calculatorMock).add(2, 3);
}Conclusión
En este tema, hemos aprendido cómo usar Mockito con JUnit para crear pruebas unitarias más efectivas. Hemos cubierto cómo configurar Mockito, crear mocks, inyectar mocks en el código, y verificar interacciones. Además, hemos visto un ejemplo práctico y proporcionado ejercicios para reforzar los conceptos aprendidos. Con estas herramientas, estarás mejor preparado para escribir pruebas unitarias robustas y mantener un código de alta calidad.
Curso de JUnit
Módulo 1: Introducción a JUnit
Módulo 2: Anotaciones Básicas de JUnit
- Entendiendo @Test
- Usando @Before y @After
- Usando @BeforeClass y @AfterClass
- Ignorando Tests con @Ignore
Módulo 3: Aserciones en JUnit
Módulo 4: Tests Parametrizados
- Introducción a los Tests Parametrizados
- Creando Tests Parametrizados
- Usando @ParameterizedTest
- Tests Parametrizados Personalizados
Módulo 5: Suites de Tests
Módulo 6: Mocking con JUnit
Módulo 7: Características Avanzadas de JUnit
Módulo 8: Mejores Prácticas y Consejos
- Escribiendo Tests Efectivos
- Organizando el Código de Tests
- Desarrollo Guiado por Tests (TDD)
- Integración Continua con JUnit
