modulo 13 di 24 / Ore 21-40
Moduli 9-16 / Checkpoint 40 ore
Testare StatoStrumento e regole di prestito
Come scrivere test per le funzioni di dominio isDisponibile, puoEsserePrestato e le transizioni di stato — con test concreti per ogni stato possibile e per le regole di transizione.
Testare StatoStrumento e regole di prestito
Questa lezione appartiene al Modulo 13 — Testare l’architettura.
Le funzioni di dominio sono le più facili da testare perché non hanno dipendenze esterne: ricevono un oggetto, applicano una regola, restituiscono un risultato. Non serve un archivio, non serve un browser. Bastano valori di input e un’asserzione.
Obiettivo della lezione
In questa lezione scrivi test concreti per isDisponibile, puoEsserePrestato e verificaTransizione del Registro. Copri tutti e quattro gli stati possibili di uno strumento e tutte le transizioni valide e non valide.
Alla fine devi avere un risultato verificabile: un file di test che gira con node da terminale e copre ogni stato e ogni regola di transizione.
Le funzioni da testare
Prima di scrivere i test, ricorda cosa fa ogni funzione:
isDisponibile(strumento)
→ true se strumento.stato === 'disponibile'
→ false per qualsiasi altro stato
puoEsserePrestato(strumento)
→ true se lo strumento è disponibile
→ false se è in_prestito, guasto o in_manutenzione
verificaTransizione(statoAttuale, statoNuovo)
→ non fa nulla se la transizione è valida
→ lancia un errore se la transizione non è permessa
Transizioni valide:
disponibile → in_prestito (apertura prestito)
disponibile → guasto (segnalazione guasto)
in_prestito → disponibile (restituzione)
in_prestito → guasto (guasto durante prestito)
guasto → in_manutenzione (avvio manutenzione)
in_manutenzione → disponibile (manutenzione completata)
Transizioni non valide:
guasto → disponibile (non si salta la manutenzione)
in_manutenzione → guasto (non si regredisce)
in_prestito → in_manutenzione (non si manda in manutenzione durante prestito)
I test da scrivere
Ogni funzione richiede un test per ogni percorso possibile:
isDisponibile — 4 test, uno per stato
disponibile → true
in_prestito → false
guasto → false
in_manutenzione → false
puoEsserePrestato — 4 test, uno per stato
disponibile → true
in_prestito → false
guasto → false
in_manutenzione → false
verificaTransizione — 6 test per transizioni valide + 3 test per transizioni non valide
Valide: non lanciano errori
Non valide: lanciano errori con messaggio leggibile
Procedura guidata
- Crea il file
test/dominio.test.js. - Importa le funzioni da
domain/regolePrestito.jsedomain/StatoStrumento.js. - Scrivi i quattro test per
isDisponibile, uno per ogni stato. - Scrivi i quattro test per
puoEsserePrestato, uno per ogni stato. - Scrivi i sei test per transizioni valide:
verificaTransizionenon deve lanciare errori. - Scrivi i tre test per transizioni non valide:
verificaTransizionedeve lanciare errori. - Esegui
node test/dominio.test.jse verifica che tutti i test passino.
Attività in classe
Compila questa tabella prima di scrivere il codice:
## Test per le funzioni di dominio
isDisponibile:
{ stato: 'disponibile' } → _______________
{ stato: 'in_prestito' } → _______________
{ stato: 'guasto' } → _______________
{ stato: 'in_manutenzione' } → _______________
puoEsserePrestato:
{ stato: 'disponibile' } → _______________
{ stato: 'in_prestito' } → _______________
{ stato: 'guasto' } → _______________
{ stato: 'in_manutenzione' } → _______________
verificaTransizione (valide — nessun errore):
disponibile → in_prestito = _______________
disponibile → guasto = _______________
in_prestito → disponibile = _______________
in_manutenzione → disponibile = _______________
verificaTransizione (non valide — errore):
guasto → disponibile = errore: _______________
in_prestito → in_manutenzione = errore: _______________
Spiegazione guidata per studiare
Testare le funzioni di dominio è il punto di partenza per qualsiasi suite di test. Sono i test più semplici da scrivere, i più veloci da eseguire e quelli che coprono le regole più importanti del sistema.
isDisponibile e puoEsserePrestato sembrano banali: una riga di codice, una condizione. Ma hanno quattro percorsi possibili (uno per ogni stato) e ognuno deve essere esplicitamente verificato. Se isDisponibile restituisce true per uno strumento guasto a causa di un typo ('guasto' scritto come 'Guasto'), un test ti lo dice subito. Senza test, scopriresti il bug solo quando uno studente tenta di prendere in prestito uno strumento guasto.
verificaTransizione è più interessante. Ha una mappa di transizioni valide e deve lanciare un errore per qualsiasi altra combinazione. Testare le transizioni valide è facile: verifichi che non vengano lanciati errori. Testare le transizioni non valide è più importante: verifichi che il sistema rifiuti esplicitamente le transizioni proibite.
La cosa fondamentale da capire è che i test di dominio non hanno bisogno di archivi né di browser. Ogni test è una funzione che passa un oggetto semplice { stato: 'guasto' } e verifica il valore restituito. Questa semplicità è la prova che il dominio è davvero separato dagli altri livelli.
Passo per passo nel progetto
- Apri
domain/StatoStrumento.jse copia i quattro valori costanti. - Apri
domain/regolePrestito.jse leggiisDisponibile,puoEsserePrestato,verificaTransizione. - Costruisci un oggetto strumento minimale per ogni test:
{ stato: StatoStrumento.GUASTO }. - Per i test su
verificaTransizione, chiama la funzione dentro untry/catchper i casi non validi. - Verifica che i test di transizione valida non lancino errori: se non c’è eccezione, il test passa.
- Verifica che i test di transizione non valida lancino errori con il messaggio corretto.
- Esegui tutti i test e conta: devono essere almeno tredici (4 + 4 + 6 valide + 3 non valide).
Esempio da leggere lentamente
Questi test coprono tutte le funzioni di dominio del Registro:
// test/dominio.test.js
import { StatoStrumento } from '../domain/StatoStrumento.js';
import {
isDisponibile,
puoEsserePrestato,
verificaTransizione
} from '../domain/regolePrestito.js';
// Helper per asserzioni
function assertEqual(ottenuto, atteso, messaggio) {
if (ottenuto !== atteso) {
throw new Error(`${messaggio}: atteso ${atteso}, ottenuto ${ottenuto}`);
}
}
function assertLanciaErrore(fn, parolaChiave) {
let errore = null;
try { fn(); } catch (e) { errore = e; }
if (!errore) throw new Error('Atteso un errore, ma non è stato lanciato');
if (!errore.message.includes(parolaChiave)) {
throw new Error(`Parola chiave "${parolaChiave}" non trovata in: "${errore.message}"`);
}
}
function assertNonLanciaErrore(fn) {
try { fn(); } catch (e) {
throw new Error('Non atteso un errore, ma è stato lanciato: ' + e.message);
}
}
// Test isDisponibile
assertEqual(isDisponibile({ stato: StatoStrumento.DISPONIBILE }), true, 'disponibile → true');
assertEqual(isDisponibile({ stato: StatoStrumento.IN_PRESTITO }), false, 'in_prestito → false');
assertEqual(isDisponibile({ stato: StatoStrumento.GUASTO }), false, 'guasto → false');
assertEqual(isDisponibile({ stato: StatoStrumento.IN_MANUTENZIONE }), false, 'in_manutenzione → false');
console.log('OK — isDisponibile (4 test)');
// Test puoEsserePrestato
assertEqual(puoEsserePrestato({ stato: StatoStrumento.DISPONIBILE }), true, 'disponibile → prestabile');
assertEqual(puoEsserePrestato({ stato: StatoStrumento.IN_PRESTITO }), false, 'in_prestito → non prestabile');
assertEqual(puoEsserePrestato({ stato: StatoStrumento.GUASTO }), false, 'guasto → non prestabile');
assertEqual(puoEsserePrestato({ stato: StatoStrumento.IN_MANUTENZIONE }), false, 'in_manutenzione → non prestabile');
console.log('OK — puoEsserePrestato (4 test)');
// Test verificaTransizione — transizioni valide
assertNonLanciaErrore(() => verificaTransizione(StatoStrumento.DISPONIBILE, StatoStrumento.IN_PRESTITO));
assertNonLanciaErrore(() => verificaTransizione(StatoStrumento.DISPONIBILE, StatoStrumento.GUASTO));
assertNonLanciaErrore(() => verificaTransizione(StatoStrumento.IN_PRESTITO, StatoStrumento.DISPONIBILE));
assertNonLanciaErrore(() => verificaTransizione(StatoStrumento.IN_PRESTITO, StatoStrumento.GUASTO));
assertNonLanciaErrore(() => verificaTransizione(StatoStrumento.GUASTO, StatoStrumento.IN_MANUTENZIONE));
assertNonLanciaErrore(() => verificaTransizione(StatoStrumento.IN_MANUTENZIONE, StatoStrumento.DISPONIBILE));
console.log('OK — verificaTransizione transizioni valide (6 test)');
// Test verificaTransizione — transizioni non valide
assertLanciaErrore(
() => verificaTransizione(StatoStrumento.GUASTO, StatoStrumento.DISPONIBILE),
'non valida'
);
assertLanciaErrore(
() => verificaTransizione(StatoStrumento.IN_MANUTENZIONE, StatoStrumento.GUASTO),
'non valida'
);
assertLanciaErrore(
() => verificaTransizione(StatoStrumento.IN_PRESTITO, StatoStrumento.IN_MANUTENZIONE),
'non valida'
);
console.log('OK — verificaTransizione transizioni non valide (3 test)');
console.log('\nTutti i test di dominio passati.');
Nota: nessuna importazione da infrastructure/, nessun archivio, nessun browser. Solo funzioni pure e valori di input.
Prova di comprensione
Prima di chiudere la lezione, rispondi per iscritto a queste domande:
- Perché i test di dominio non hanno bisogno di un archivio?
- Cosa significa che
verificaTransizioneè una funzione “pura”? - Se aggiungi un quinto stato
'dismesso'al sistema, quanti test devi aggiungere almeno? - Perché testare le transizioni non valide è importante quanto testare quelle valide?
Una risposta accettabile usa i nomi reali delle funzioni del progetto.
Errori da evitare
- non testare tutti e quattro gli stati per
isDisponibile— un typo in una costante sarebbe invisibile; - testare solo le transizioni valide e dimenticare quelle non valide;
- costruire oggetti strumento complessi quando basta
{ stato: 'guasto' }; - importare qualcosa da
infrastructure/nel file di test del dominio — non serve mai; - non avere la funzione helper
assertLanciaErroree ripetere il patterntry/catchper ogni test.
Prodotto da consegnare
Crea il file test/dominio.test.js con almeno tredici test: quattro per isDisponibile, quattro per puoEsserePrestato, sei per transizioni valide e tre per transizioni non valide. Il file deve girare con node test/dominio.test.js senza errori.
Checklist di chiusura
Prima di chiudere la lezione, controlla:
- tutti e quattro gli stati sono testati in
isDisponibile; - tutti e quattro gli stati sono testati in
puoEsserePrestato; - le sei transizioni valide non lanciano errori;
- le tre transizioni non valide lanciano errori con il messaggio corretto;
- il file di test non importa nulla da
infrastructure/.
Risultato atteso
Alla fine lo studente deve saper dire:
Ho scritto tredici test per le funzioni di dominio del Registro.
isDisponibile: quattro test, uno per ogni stato — solo 'disponibile' restituisce true.
puoEsserePrestato: quattro test, risultato uguale a isDisponibile per questo progetto.
verificaTransizione: sei test per transizioni valide (nessun errore atteso),
tre test per transizioni non valide (errore atteso con "non valida" nel messaggio).
I test di dominio non usano archivi né browser: sono funzioni pure su oggetti semplici.
Se questa spiegazione non è possibile, la lezione non è ancora davvero conclusa.