modulo 14 di 24 / Ore 21-40
Moduli 9-16 / Checkpoint 40 ore
Preparare il refactoring con test minimi
Come preparare il Registro per un refactoring sicuro: identificare le funzioni da refactorare, scrivere i test minimi necessari e verificare che passino prima di iniziare.
Preparare il refactoring con test minimi
Questa lezione appartiene al Modulo 13 — Testare l’architettura.
Obiettivo della lezione
Definire il numero minimo di test necessari per refactorare una funzione del Registro in modo sicuro — non il massimo possibile, ma quelli che proteggono i comportamenti che non devono cambiare.
Alla fine sai quale funzione vuoi refactorare, hai scritto i test minimi e puoi procedere con sicurezza.
Perché serve nel percorso
“Test minimi” significa i test strettamente necessari per rilevare una regressione. Non serve la copertura totale — serve la protezione delle regole critiche. Con troppi test si rallenta senza guadagnare sicurezza; con troppo pochi si rischia di rompere qualcosa senza accorgersene.
Nel Registro del laboratorio
Supponi di voler refactorare registraPrestito — la funzione è cresciuta e fa troppo. Prima di toccarla, devi sapere esattamente cosa deve continuare a funzionare dopo.
Passo 1 — Lista i comportamenti critici:
registraPrestito deve continuare a:
1. Rifiutare strumenti non trovati (STRUMENTO_NON_TROVATO)
2. Rifiutare strumenti guasti (STRUMENTO_GUASTO_NON_PRESTABILE)
3. Rifiutare strumenti già in prestito (STRUMENTO_GIA_IN_PRESTITO)
4. Salvare il prestito nell'archivio
5. Cambiare lo stato dello strumento a "in_prestito"
Questi sono i comportamenti minimi. Non testi i dettagli interni — testi solo cosa deve restare uguale.
Passo 2 — Scrivi un test per ciascuno:
// test/application/registraPrestito.test.js
import { creaArchivioStrumentiFake } from "../fakes/archivioStrumentiFake.js";
import { creaArchivioPrestitiFake } from "../fakes/archivioPrestitiFake.js";
import { registraPrestito } from "../../src/application/registraPrestito.js";
// Helper per creare archivi comuni nei test
function creaArchivi(stato = "disponibile") {
return {
strumenti: creaArchivioStrumentiFake([
{ id: "str-001", nome: "Oscilloscopio", categoria: "Misura", stato }
]),
prestiti: creaArchivioPrestitiFake()
};
}
// 1. Strumento non trovato
test("lancia STRUMENTO_NON_TROVATO per ID inesistente", () => {
const { strumenti, prestiti } = creaArchivi();
expect(() => registraPrestito({ strumentoId: "non-esiste", studenteId: "stu-01" }, strumenti, prestiti))
.toThrow("STRUMENTO_NON_TROVATO");
});
// 2. Strumento guasto
test("lancia STRUMENTO_GUASTO_NON_PRESTABILE per strumento guasto", () => {
const { strumenti, prestiti } = creaArchivi("guasto");
expect(() => registraPrestito({ strumentoId: "str-001", studenteId: "stu-01" }, strumenti, prestiti))
.toThrow("STRUMENTO_GUASTO_NON_PRESTABILE");
});
// 3. Strumento già in prestito
test("lancia STRUMENTO_GIA_IN_PRESTITO per strumento in prestito", () => {
const { strumenti, prestiti } = creaArchivi("in_prestito");
expect(() => registraPrestito({ strumentoId: "str-001", studenteId: "stu-01" }, strumenti, prestiti))
.toThrow("STRUMENTO_GIA_IN_PRESTITO");
});
// 4. Salva il prestito
test("salva il prestito nell'archivio per strumento disponibile", () => {
const { strumenti, prestiti } = creaArchivi("disponibile");
registraPrestito({ strumentoId: "str-001", studenteId: "stu-01" }, strumenti, prestiti);
expect(prestiti.trovaTutti()).toHaveLength(1);
});
// 5. Cambia lo stato dello strumento
test("cambia lo stato dello strumento a in_prestito", () => {
const { strumenti, prestiti } = creaArchivi("disponibile");
registraPrestito({ strumentoId: "str-001", studenteId: "stu-01" }, strumenti, prestiti);
expect(strumenti.trovaPerId("str-001").stato).toBe("in_prestito");
});
Passo 3 — Esegui i test e verifica che passino tutti.
Solo dopo puoi iniziare il refactoring.
Procedura guidata
- Scegli la funzione da refactorare.
- Elenca i comportamenti critici (massimo 5-7 punti).
- Scrivi un test per ogni comportamento critico.
- Esegui i test: devono passare tutti prima di iniziare.
- Se qualcuno fallisce: correggi il bug prima di procedere con il refactoring.
- Inizia il refactoring mantenendo i test visibili.
Attività in classe
Fai lo stesso esercizio per chiudiPrestito. Elenca i comportamenti critici e scrivi i test minimi:
## Test minimi per chiudiPrestito
Comportamenti critici:
1. ...
2. ...
3. ...
Test scritti:
- ...
- ...
- ...
Tutti passano prima del refactoring? sì/no
Spiegazione guidata per studiare
I test minimi non sono il numero minimo teorico — sono il numero minimo pratico per sentirti sicuro.
Come decidere quali test scrivere:
- testa ogni codice errore che la funzione può lanciare;
- testa l’effetto collaterale principale (cosa viene salvato, cosa viene modificato);
- testa il caso felice base (funziona con dati validi);
- non testare l’implementazione interna (quale funzione viene chiamata dentro).
Quanti test sono “minimi”? Per registraPrestito sono 5. Per una funzione semplice come validaNomeStrumento potrebbero essere 3. Non esiste una risposta universale — la risposta è: “quanti mi servono per essere sicuro che il comportamento esterno non sia cambiato dopo il refactoring?”
Il ciclo completo:
1. Elenca i comportamenti critici
2. Scrivi i test minimi (uno per comportamento)
3. Esegui i test — tutti devono passare
4. Fai il refactoring in passi piccoli
5. Esegui i test dopo ogni passo
6. Se un test fallisce: il refactoring ha rotto qualcosa — torna indietro
Il punto 6 è il valore reale dei test: ti danno il feedback immediato che qualcosa è andato storto, senza dover testare manualmente l’intera applicazione.
Passo per passo nel progetto
- Apri la funzione che vuoi refactorare.
- Leggi il codice e scrivi su carta cosa fa (non come lo fa).
- Trasforma ogni “cosa fa” in un test.
- Esegui i test con
npm test. - Se un test fallisce: il codice attuale ha un bug — documentalo e correggilo.
- Tieni i test aperti mentre fai il refactoring.
Prova di comprensione
- Perché i test vanno eseguiti prima del refactoring e non solo dopo?
- Cosa significa che un test è “minimo” ma non “insufficiente”?
- Se scrivi 20 test per una funzione, stai preparando un buon refactoring?
- Cosa fai se un test fallisce dopo il primo passo di refactoring?
Errori da evitare
- scrivere test dopo il refactoring — non proteggono il comportamento originale;
- scrivere test che testano l’implementazione interna — si rompono ad ogni refactoring;
- non eseguire i test dopo ogni passo di refactoring — il ciclo di feedback si allunga;
- ignorare un test che fallisce e continuare il refactoring — stai accumulando debito.
Prodotto da consegnare
L’elenco dei comportamenti critici della funzione scelta, i test minimi scritti e il run iniziale che li mostra tutti verdi. Questo è il punto di partenza sicuro per il refactoring.
Checklist di chiusura
- i comportamenti critici sono elencati (non il “come” ma il “cosa”)
- c’è almeno un test per ogni comportamento critico
- ogni errore lanciato dalla funzione ha il suo test
- i test passano tutti prima di iniziare il refactoring
- nessun test dipende dall’implementazione interna
Risultato atteso
Ho scelto registraPrestito come funzione da refactorare.
Ho elencato 5 comportamenti critici e scritto 5 test corrispondenti.
Tutti e 5 i test passano prima del refactoring.
Ho il punto di partenza sicuro per procedere con il refactoring in passi piccoli.
Il prossimo passo è estrarre la logica di verifica stato in una funzione separata.