Tag: junit, mockito, java, testing, unit-testing, mocks, stubbing
Livello: intermedio
TL;DR: Riferimento rapido per lo unit testing in Java. Copre l'isolamento delle dipendenze con Mockito e la validazione dei risultati tramite le asserzioni di JUnit.
JUnit è il framework di unit testing standard per applicazioni Java.
Mockito permette di creare oggetti mock per isolare il componente in test dalle sue dipendenze.
L'annotazione @Mock genera un'istanza fittizia di una classe o di un'interfaccia.
L'annotazione @InjectMocks istanzia la classe in test e inietta automaticamente i mock nei suoi campi.
Lo stubbing definisce il comportamento simulato dei mock in scenari specifici.
La verifica assicura che il componente abbia interagito correttamente con le sue dipendenze.
L'annotazione @Spy crea un mock parziale, eseguendo i metodi reali a meno di stubbing esplicito.
Le asserzioni validano l'output effettivo del codice rispetto al risultato atteso.
Q: Qual è la differenza tra @Mock e @Spy?R: Uso @Mock per creare un oggetto completamente fittizio con comportamenti vuoti di default. Uso @Spy per avvolgere un'istanza reale e mantenere i comportamenti originali, stubbando solo cio' che mi serve.
Q: Come verifichi che un metodo lanci una specifica eccezione?R: Utilizzo il costrutto assertThrows di JUnit 5, passando la classe dell'eccezione attesa e una lambda che esegue il metodo incriminato.
Q: Come testi un metodo void con Mockito?R: Non potendo verificare il valore di ritorno, uso verify(mock).metodo() per accertarmi che sia stato invocato, oppure doThrow() se devo simulare un'eccezione.
Dimenticare di abilitare Mockito nel test tramite @ExtendWith(MockitoExtension.class).
Applicare @InjectMocks su un'interfaccia invece che sull'implementazione concreta da testare.
Tentare di fare stubbing su metodi final, private o static senza aver incluso e configurato mockito-inline.
Usare matcher generici (come any()) insieme a valori espliciti nella stessa chiamata di metodo senza avvolgere i valori in eq().
```import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Optional;
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void shouldReturnUserWhenFound() {
// Arrange (Stubbing)
User mockUser = new User("Alice");
when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));
// Act
User result = userService.getUserById(1L);
// Assert
assertEquals("Alice", result.getName());
// Verify
verify(userRepository, times(1)).findById(1L);
}
@Test
void shouldThrowExceptionWhenUserNotFound() {
// Arrange
when(userRepository.findById(2L)).thenReturn(Optional.empty());
// Act & Assert
assertThrows(UserNotFoundException.class, () -> {
userService.getUserById(2L);
});
}
}
```