En aquest tema, aprendrem com utilitzar Mockito, una popular llibreria de mocking per a Java, juntament amb JUnit per crear tests més robustos i flexibles. Mockito ens permet crear mocks d'objectes per simular el comportament de les dependències en els nostres tests.
Què és Mockito?
Mockito és una llibreria de mocking per a Java que permet crear objectes simulats (mocks) per a les nostres proves unitàries. Els mocks ens permeten aïllar el codi que estem provant de les seves dependències, facilitant la detecció d'errors i la verificació del comportament del codi.
Configuració de Mockito
Abans de començar a utilitzar Mockito amb JUnit, hem d'afegir la dependència de Mockito al nostre projecte. Si estem utilitzant Maven, podem afegir la següent dependència al nostre pom.xml
:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.11.2</version> <scope>test</scope> </dependency>
Si estem utilitzant Gradle, podem afegir la següent línia al nostre build.gradle
:
Creant Mocks amb Mockito
Per crear un mock amb Mockito, utilitzem la funció Mockito.mock()
. A continuació, es mostra un exemple de com crear un mock 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; class UserServiceTest { @Test void testGetUser() { // Crear un mock de la classe UserRepository UserRepository mockRepository = mock(UserRepository.class); // Definir el comportament del mock User mockUser = new User("John", "Doe"); when(mockRepository.findUserById(1)).thenReturn(mockUser); // Crear una instància de la classe que estem provant UserService userService = new UserService(mockRepository); // Executar el mètode que estem provant User result = userService.getUser(1); // Verificar el resultat assertEquals("John", result.getFirstName()); assertEquals("Doe", result.getLastName()); } }
Explicació del Codi
- Creació del Mock: Utilitzem
mock(UserRepository.class)
per crear un mock de la classeUserRepository
. - Definició del Comportament del Mock: Utilitzem
when(mockRepository.findUserById(1)).thenReturn(mockUser)
per definir el comportament del mock. Quan es crida al mètodefindUserById(1)
, el mock retornarà l'objectemockUser
. - Creació de la Classe a Provar: Creem una instància de
UserService
passant-li el mockmockRepository
. - Execució del Mètode a Provar: Cridem al mètode
getUser(1)
deUserService
. - Verificació del Resultat: Utilitzem
assertEquals
per verificar que el resultat és el que esperem.
Verificant Interaccions amb Mockito
Mockito també ens permet verificar que els mètodes dels mocks han estat cridats amb els paràmetres correctes. A continuació, es mostra un exemple de com fer-ho:
import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; class UserServiceTest { @Test void testGetUser() { UserRepository mockRepository = mock(UserRepository.class); User mockUser = new User("John", "Doe"); when(mockRepository.findUserById(1)).thenReturn(mockUser); UserService userService = new UserService(mockRepository); User result = userService.getUser(1); assertEquals("John", result.getFirstName()); assertEquals("Doe", result.getLastName()); // Verificar que el mètode findUserById ha estat cridat amb el paràmetre 1 verify(mockRepository).findUserById(1); } }
Explicació del Codi
- Verificació de la Interacció: Utilitzem
verify(mockRepository).findUserById(1)
per verificar que el mètodefindUserById
del mockmockRepository
ha estat cridat amb el paràmetre1
.
Exercici Pràctic
Exercici
Crea un test per a la classe OrderService
que utilitzi Mockito per simular el comportament de la seva dependència OrderRepository
. Verifica que el mètode placeOrder
crida al mètode saveOrder
del OrderRepository
amb l'ordre correcta.
class OrderService { private final OrderRepository orderRepository; public OrderService(OrderRepository orderRepository) { this.orderRepository = orderRepository; } public void placeOrder(Order order) { orderRepository.saveOrder(order); } } interface OrderRepository { void saveOrder(Order order); } class Order { private final String product; private final int quantity; public Order(String product, int quantity) { this.product = product; this.quantity = quantity; } // Getters public String getProduct() { return product; } public int getQuantity() { return quantity; } }
Solució
import static org.mockito.Mockito.*; import org.junit.jupiter.api.Test; class OrderServiceTest { @Test void testPlaceOrder() { // Crear un mock de la classe OrderRepository OrderRepository mockRepository = mock(OrderRepository.class); // Crear una instància de la classe que estem provant OrderService orderService = new OrderService(mockRepository); // Crear una ordre de prova Order order = new Order("Laptop", 1); // Executar el mètode que estem provant orderService.placeOrder(order); // Verificar que el mètode saveOrder ha estat cridat amb l'ordre correcta verify(mockRepository).saveOrder(order); } }
Explicació del Codi
- Creació del Mock: Utilitzem
mock(OrderRepository.class)
per crear un mock de la classeOrderRepository
. - Creació de la Classe a Provar: Creem una instància de
OrderService
passant-li el mockmockRepository
. - Creació de l'Ordre de Prova: Creem una instància de
Order
amb els valors "Laptop" i 1. - Execució del Mètode a Provar: Cridem al mètode
placeOrder(order)
deOrderService
. - Verificació de la Interacció: Utilitzem
verify(mockRepository).saveOrder(order)
per verificar que el mètodesaveOrder
del mockmockRepository
ha estat cridat amb l'ordreorder
.
Conclusió
En aquest tema, hem après com utilitzar Mockito amb JUnit per crear mocks i verificar interaccions. Hem vist com configurar Mockito, crear mocks, definir el seu comportament i verificar que els mètodes dels mocks han estat cridats amb els paràmetres correctes. Aquests coneixements ens permetran escriure tests més robustos i flexibles, aïllant el codi que estem provant de les seves dependències.
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