En aquest tema, aprendrem com crear mocks utilitzant la biblioteca Mockito amb JUnit. Els mocks són objectes simulats que imiten el comportament d'objectes reals en un entorn controlat. Són especialment útils per aïllar el codi que estem provant de les seves dependències externes.
Objectius
- Entendre què són els mocks i per què són útils.
- Aprendre a crear mocks amb Mockito.
- Veure exemples pràctics de com utilitzar mocks en tests.
Què és un Mock?
Un mock és un objecte que simula el comportament d'un altre objecte. En el context de les proves unitàries, els mocks permeten:
- Aïllar el codi que estem provant de les seves dependències.
- Simular diferents escenaris de prova.
- Verificar que les interaccions amb les dependències es realitzen correctament.
Configuració de Mockito
Abans de començar a crear mocks, necessitem configurar Mockito en el nostre projecte. Si estàs utilitzant Maven, afegeix la següent dependència al teu pom.xml
:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.11.2</version> <scope>test</scope> </dependency>
Creant Mocks amb Mockito
Exemple Bàsic
A continuació, veurem un exemple bàsic de com crear un mock amb Mockito i utilitzar-lo en un test de JUnit.
import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import org.mockito.Mockito; class UserServiceTest { @Test void testGetUserName() { // Crear un mock de la classe UserRepository UserRepository mockRepository = Mockito.mock(UserRepository.class); // Definir el comportament del mock when(mockRepository.findUserById(1)).thenReturn(new User(1, "John Doe")); // Utilitzar el mock en el test UserService userService = new UserService(mockRepository); String userName = userService.getUserName(1); // Verificar el resultat assertEquals("John Doe", userName); } }
Explicació del Codi
- Crear el Mock: Utilitzem
Mockito.mock(UserRepository.class)
per crear un mock de la classeUserRepository
. - Definir el Comportament del Mock: Utilitzem
when(mockRepository.findUserById(1)).thenReturn(new User(1, "John Doe"))
per definir el comportament del mock. Això significa que quan es cridi al mètodefindUserById(1)
, el mock retornarà un objecteUser
amb l'ID 1 i el nom "John Doe". - Utilitzar el Mock: Passem el mock al constructor de
UserService
i utilitzem el servei per obtenir el nom de l'usuari. - Verificar el Resultat: Utilitzem
assertEquals("John Doe", userName)
per verificar que el nom de l'usuari retornat és "John Doe".
Verificant Interaccions
A més de definir el comportament dels mocks, també podem verificar que les interaccions amb els mocks es realitzen correctament.
import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import org.mockito.Mockito; class UserServiceTest { @Test void testGetUserName() { // Crear un mock de la classe UserRepository UserRepository mockRepository = Mockito.mock(UserRepository.class); // Definir el comportament del mock when(mockRepository.findUserById(1)).thenReturn(new User(1, "John Doe")); // Utilitzar el mock en el test UserService userService = new UserService(mockRepository); String userName = userService.getUserName(1); // Verificar el resultat assertEquals("John Doe", userName); // Verificar que el mètode findUserById(1) es va cridar exactament una vegada verify(mockRepository, times(1)).findUserById(1); } }
Explicació del Codi
- Verificar Interaccions: Utilitzem
verify(mockRepository, times(1)).findUserById(1)
per verificar que el mètodefindUserById(1)
es va cridar exactament una vegada.
Exercici Pràctic
Exercici
Crea un test per a una classe OrderService
que depèn d'una classe PaymentProcessor
. Utilitza Mockito per crear un mock de PaymentProcessor
i verifica que el mètode processPayment
es crida amb els paràmetres correctes.
Solució
import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import org.mockito.Mockito; class OrderServiceTest { @Test void testProcessOrder() { // Crear un mock de la classe PaymentProcessor PaymentProcessor mockProcessor = Mockito.mock(PaymentProcessor.class); // Definir el comportament del mock when(mockProcessor.processPayment(anyDouble())).thenReturn(true); // Utilitzar el mock en el test OrderService orderService = new OrderService(mockProcessor); boolean result = orderService.processOrder(100.0); // Verificar el resultat assertTrue(result); // Verificar que el mètode processPayment(100.0) es va cridar exactament una vegada verify(mockProcessor, times(1)).processPayment(100.0); } }
Explicació del Codi
- Crear el Mock: Utilitzem
Mockito.mock(PaymentProcessor.class)
per crear un mock de la classePaymentProcessor
. - Definir el Comportament del Mock: Utilitzem
when(mockProcessor.processPayment(anyDouble())).thenReturn(true)
per definir el comportament del mock. Això significa que quan es cridi al mètodeprocessPayment
amb qualsevol valordouble
, el mock retornaràtrue
. - Utilitzar el Mock: Passem el mock al constructor de
OrderService
i utilitzem el servei per processar una ordre. - Verificar el Resultat: Utilitzem
assertTrue(result)
per verificar que el resultat éstrue
. - Verificar Interaccions: Utilitzem
verify(mockProcessor, times(1)).processPayment(100.0)
per verificar que el mètodeprocessPayment(100.0)
es va cridar exactament una vegada.
Conclusió
En aquest tema, hem après com crear mocks utilitzant Mockito i com utilitzar-los en tests de JUnit. Els mocks són una eina poderosa per aïllar el codi que estem provant de les seves dependències i verificar que les interaccions es realitzen correctament. En el següent tema, explorarem com verificar interaccions amb més detall.
Curs de JUnit
Mòdul 1: Introducció a JUnit
Mòdul 2: Anotacions Bàsiques de JUnit
- Entenent @Test
- Utilitzant @Before i @After
- Utilitzant @BeforeClass i @AfterClass
- Ignorant Tests amb @Ignore
Mòdul 3: Assertions a JUnit
Mòdul 4: Tests Parametritzats
- Introducció als Tests Parametritzats
- Creant Tests Parametritzats
- Utilitzant @ParameterizedTest
- Tests Parametritzats Personalitzats
Mòdul 5: Suites de Test
Mòdul 6: Mocking amb JUnit
Mòdul 7: Funcions Avançades de JUnit
Mòdul 8: Millors Pràctiques i Consells
- Escrivint Tests Efectius
- Organitzant el Codi de Test
- Desenvolupament Guiat per Tests (TDD)
- Integració Contínua amb JUnit