Java Unit Testing with JUnit - Tutorial - How to Create And Use Unit Tests
Il testing su Java è un processo fondamentale nello sviluppo software volto a garantire che il codice funzioni correttamente e risponda alle aspettative.
In tutti gli ambienti di sviluppo, indipendentemente dal processo di produzione del codice adottato, la fase di testing è spesso trascurata. Questo accade per vari motivi, come la mancanza di tempo, la scarsa volontà degli sviluppatori, o semplicemente perché ritenuta di poco interesse. Tuttavia, il testing è fondamentale per garantire la qualità e la robustezza del software.
Il testing del software è l’insieme di attività svolte per verificare che un’applicazione soddisfi i requisiti specificati e sia priva di errori. Consiste nell’eseguire un programma con l’intento di trovare bug o difetti, garantire che il comportamento del software sia conforme alle aspettative e validare che i risultati siano corretti.
Questi sono test che verificano la funzionalità di unità isolate di codice, come metodi o classi singole.
Questi test verificano l’interazione tra diverse unità o componenti del sistema.
Questi test verificano che il sistema soddisfi i requisiti funzionali specificati.
Questi test assicurano che le modifiche al codice non abbiano introdotto nuovi bug.
Questi test verificano il comportamento del sistema sotto carico e la sua performance.
Questi test verificano l’intero flusso di lavoro dall’inizio alla fine, come farebbe un utente reale.
Questi test verificano che l’interfaccia utente funzioni correttamente.
JUnit fornisce diverse annotazioni e strumenti per categorizzare e gestire i test:
Annotazione | Utilizzo |
---|---|
@Test | per annotare i metodi di test |
@Before | per annotare un metodo da eseguire prima dell’esecuzione di un test case (ad esempio l’apertura di una connessione ad un database, o uno stream) |
@After | per annotare un metodo da eseguire dopo l’esecuzione di un test case (chiusura di risorse aperte in precedenza) |
@BeforeClass | come @Before ma solo all’inizio dell’esecuzione del test |
@AfterClass | come @After ma solo alla fine dell’esecuzione del test |
@BeforeEach | Esegue il codice prima ogni metodo di test. |
@AfterEach | Esegue il codice dopo ogni metodo di test. |
@BeforeAll | Esegue il codice prima ogni metodo di test. |
@AfterAll | Esegue il codice una volta dopo tutti i metodi di test. |
@Ignore / @Disabled | utilizzata per evitare l’esecuzione di un test (evitando di commentare) |
@Tag | Categoria di test (utile per filtrare ed eseguire solo determinati gruppi di test). |
DeterminatoreVoto.java
Questa classe contiene un metodo per convertire un voto numerico in una lettera, secondo una scala prestabilita.
public class DeterminatoreVoto {
public char determinaVotoInLettera (int voto) {
if (voto < 0) {
throw new IllegalArgumentException("Il voto non puo' essere negativo");
}
else if (voto > 100) {
throw new IllegalArgumentException("Il voto non puo' essere superiore a 100");
}
else if (voto < 60) {
return 'F';
}
else if (voto < 70) {
return 'D';
}
else if (voto < 80) {
return 'C';
}
else if (voto < 90) {
return 'B';
}
else {
return 'A';
}
}
}
DeterminatoreVotoTest.java
Questa classe utilizza JUnit per verificare che il metodo determinaVotoInLettera
funzioni correttamente. Include vari test case per coprire diverse situazioni.
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import org.junit.Before;
import org.junit.After;
public class DeterminatoreVotoTest {
private DeterminatoreVoto determinatore;
@Before
public void startup() {
determinatore = new DeterminatoreVoto();
}
@After
public void cleanup() {
determinatore = null;
}
@Test
public void testCinquantacinqueDovrebbeRitornareF() {
char lettera = determinatore.determinaVotoInLettera(55);
assertEquals('F', lettera);
}
@Test
public void testSessantacinqueDovrebbeRitornareD() {
char lettera = determinatore.determinaVotoInLettera(65);
assertEquals('D', lettera);
}
@Test
public void testSettantacinqueDovrebbeRitornareC() {
char lettera = determinatore.determinaVotoInLettera(75);
assertEquals('C', lettera);
}
@Test
public void testOttantacinqueDovrebbeRitornareB() {
char lettera = determinatore.determinaVotoInLettera(85);
assertEquals('B', lettera);
}
@Test
public void testNovantacinqueDovrebbeRitornareA() {
char lettera = determinatore.determinaVotoInLettera(95);
assertEquals('A', lettera);
}
@Test
public void testVotoNegativoDovrebbeRitornareException() {
assertThrows(IllegalArgumentException.class, () -> {
determinatore.determinaVotoInLettera(-10);
});
}
@Test
public void testVotoEccessivoDovrebbeRitornareException() {
assertThrows(IllegalArgumentException.class, () -> {
determinatore.determinaVotoInLettera(101);
});
}
@Test
public void testCheNonRestituisceNull() {
char lettera = determinatore.determinaVotoInLettera(75);
assertNotNull(lettera);
}
}
DeterminatoreVotoTest2.java (esempio appena più complesso)
Utilizza un array bidimensionale per contenere i dati di test e un ciclo per eseguire i test in modo parametrizzato.
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
public class DeterminatoreVotoTest2 {
private DeterminatoreVoto determinatore = new DeterminatoreVoto();
@Test
public void testVoti() {
Object[][] testData = {
{55, 'F'},
{65, 'D'},
{75, 'C'},
{85, 'B'},
{95, 'A'},
{60, 'D'},
{70, 'C'},
{80, 'B'},
{90, 'A'},
{-10, "EXCEPTION"},
{101, "EXCEPTION"}
};
for (Object[] data : testData) {
int voto = (int) data[0];
Object expected = data[1];
if (expected.equals("EXCEPTION")) {
assertThrows(IllegalArgumentException.class, () -> {
determinatore.determinaVotoInLettera(voto);
});
} else {
char expectedLetter = (char) expected;
char lettera = determinatore.determinaVotoInLettera(voto);
assertEquals(expectedLetter, lettera);
}
}
}
}