modulo 13 di 24 / Ore 21-40
Moduli 9-16 / Checkpoint 40 ore
Fake repository in memoria per i test
Come costruire un fake repository in memoria per testare i casi d'uso del Registro: implementazione con array, stesso contratto dell'adapter reale, reset tra test, con codice concreto.
Fake repository in memoria per i test
Questa lezione appartiene al Modulo 13 — Testare l’architettura.
Obiettivo della lezione
Costruire un fake repository in memoria che rispetti lo stesso contratto dell’adapter di localStorage, in modo da testare i casi d’uso del Registro senza toccare il browser, localStorage o il DOM.
Alla fine avrai un archivioStrumentiFake e un archivioPrestitiFake usabili nei test, con reset tra un test e l’altro.
Perché serve nel percorso
I casi d’uso (registraStrumento, registraPrestito, chiudiPrestito) ricevono l’archivio come dipendenza. Questo significa che puoi passare un archivio finto nei test — senza bisogno di localStorage, senza browser, senza setup complesso. Il test è veloce, isolato e ripetibile.
Nel Registro del laboratorio
Il contratto dell’archivio strumenti è definito dalle operazioni che i casi d’uso usano:
// Contratto atteso da registraStrumento e cercaStrumenti:
// - salva(strumento): void
// - trovaTutti(): Strumento[]
// - trovaPerId(id): Strumento | undefined
// - aggiorna(strumento): void
Il fake deve implementare esattamente questo contratto usando un array in memoria:
// test/fakes/archivioStrumentiFake.js
export function creaArchivioStrumentiFake(strumentiIniziali = []) {
let strumenti = [...strumentiIniziali];
return {
salva(strumento) {
strumenti.push({ ...strumento });
},
trovaTutti() {
return [...strumenti];
},
trovaPerId(id) {
return strumenti.find(s => s.id === id);
},
aggiorna(strumentoAggiornato) {
strumenti = strumenti.map(s =>
s.id === strumentoAggiornato.id ? { ...strumentoAggiornato } : s
);
},
// Helper per i test: resetta lo stato
_reset(nuoviStrumenti = []) {
strumenti = [...nuoviStrumenti];
}
};
}
Procedura guidata
- Crea la cartella
test/fakes/se non esiste. - Crea
archivioStrumentiFake.jscon la funzionecreaArchivioStrumentiFake. - Crea
archivioPrestitiFake.jscon la funzionecreaArchivioPrestitiFake. - Scrivi un test di base che verifica il fake stesso (salva, trova, aggiorna).
- Usa i fake in un test di caso d’uso (
registraStrumento,registraPrestito). - Verifica che il fake sia resettato tra test diversi.
Attività in classe
Implementa il fake per i prestiti seguendo lo stesso schema:
// test/fakes/archivioPrestitiFake.js
export function creaArchivioPrestitiFake(prestitiIniziali = []) {
let prestiti = [...prestitiIniziali];
return {
salva(prestito) {
prestiti.push({ ...prestito });
},
trovaTutti() {
return [...prestiti];
},
trovaPerId(id) {
// Scrivi questa riga
},
trovaAperti() {
// Scrivi questa riga: filtra prestiti con chiusura === null
},
aggiorna(prestitoAggiornato) {
// Scrivi questa riga
}
};
}
Poi scrivi questo test e verifica che passi:
// test/application/registraPrestito.test.js
import { creaArchivioStrumentiFake } from "../fakes/archivioStrumentiFake.js";
import { creaArchivioPrestitiFake } from "../fakes/archivioPrestitiFake.js";
import { registraPrestito } from "../../src/application/registraPrestito.js";
test("registra un prestito per uno strumento disponibile", () => {
const strumentiFake = creaArchivioStrumentiFake([
{ id: "str-001", nome: "Oscilloscopio", categoria: "Misura", stato: "disponibile" }
]);
const prestitiFake = creaArchivioPrestitiFake();
registraPrestito(
{ strumentoId: "str-001", studenteId: "stu-042" },
strumentiFake,
prestitiFake
);
const prestitiSalvati = prestitiFake.trovaTutti();
expect(prestitiSalvati).toHaveLength(1);
expect(prestitiSalvati[0].strumentoId).toBe("str-001");
expect(prestitiSalvati[0].chiusura).toBeNull();
// Lo stato dello strumento deve essere aggiornato
const strumento = strumentiFake.trovaPerId("str-001");
expect(strumento.stato).toBe("in_prestito");
});
test("lancia errore per uno strumento guasto", () => {
const strumentiFake = creaArchivioStrumentiFake([
{ id: "str-001", nome: "Trapano", categoria: "Utensile", stato: "guasto" }
]);
const prestitiFake = creaArchivioPrestitiFake();
expect(() =>
registraPrestito({ strumentoId: "str-001", studenteId: "stu-042" }, strumentiFake, prestitiFake)
).toThrow("STRUMENTO_GUASTO_NON_PRESTABILE");
});
Spiegazione guidata per studiare
Il fake repository è diverso da un mock. Un mock registra le chiamate e le verifica dopo. Un fake è un’implementazione reale che usa la memoria invece del disco — si comporta come l’adapter vero, ma non persiste nulla tra le esecuzioni.
Il vantaggio è che i test parlano in termini di comportamento, non di chiamate:
// Con mock (verifica le chiamate):
expect(archivio.salva).toHaveBeenCalledWith(expect.objectContaining({ stato: "in_prestito" }));
// Con fake (verifica il risultato):
expect(strumentiFake.trovaPerId("str-001").stato).toBe("in_prestito");
Il secondo approccio è più robusto: non fallisce se rinomini il metodo interno o cambi l’implementazione, finché il comportamento finale è lo stesso.
Importante: copia difensiva. Nota che nel fake tutte le operazioni di lettura restituiscono copie ([...strumenti], { ...strumento }). Questo evita che il test possa modificare accidentalmente lo stato interno del fake attraverso l’oggetto restituito.
Reset tra test. Se usi Jest o Vitest, ogni test deve partire da uno stato pulito. Il modo più semplice è creare un nuovo fake in ogni test, invece di condividere un’istanza globale:
// NON fare così — lo stato si accumula tra test
const archivio = creaArchivioStrumentiFake();
test("test 1", () => { /* aggiunge strumenti */ });
test("test 2", () => { /* vede gli strumenti del test 1 */ }); // BUG
// Fai così — ogni test parte pulito
test("test 1", () => {
const archivio = creaArchivioStrumentiFake();
// ...
});
test("test 2", () => {
const archivio = creaArchivioStrumentiFake();
// ...
});
Passo per passo nel progetto
- Crea
test/fakes/archivioStrumentiFake.jscon le funzionisalva,trovaTutti,trovaPerId,aggiorna. - Crea
test/fakes/archivioPrestitiFake.jscon le stesse funzioni piùtrovaAperti. - Scrivi un test che verifica che
salvaseguito datrovaPerIdrestituisce lo stesso strumento. - Scrivi un test che verifica che
aggiornacambia lo stato di uno strumento esistente. - Usa i fake nel test di
registraPrestito— verifica il caso felice e il caso di errore. - Usa i fake nel test di
chiudiPrestito— verifica che un prestito già chiuso non si chiude di nuovo.
Prova di comprensione
- Qual è la differenza tra un fake repository e un mock?
- Perché le funzioni di lettura del fake restituiscono copie invece dei riferimenti originali?
- Come si garantisce che ogni test parta da uno stato pulito?
- Quale caso d’uso del Registro è più facile da testare con il fake — e perché?
Errori da evitare
- condividere un’istanza di fake tra più test senza resettarla — i test si influenzano a vicenda;
- restituire il riferimento diretto all’array interno invece di una copia — il test può corrompere lo stato;
- aggiungere nel fake funzioni che non esistono nell’adapter reale — il fake diventa incompatibile;
- usare il fake per testare il mapping o il formato di salvataggio — quelli vanno testati separatamente.
Prodotto da consegnare
I file test/fakes/archivioStrumentiFake.js e test/fakes/archivioPrestitiFake.js, con almeno tre test che usano i fake per verificare comportamenti reali dei casi d’uso del Registro.
Checklist di chiusura
- il fake implementa lo stesso contratto dell’adapter di localStorage
- ogni funzione di lettura restituisce una copia, non un riferimento
- ogni test crea un nuovo fake (nessuna istanza condivisa)
- il test del caso felice e del caso di errore passano entrambi
- i test non importano nulla da
localStorage,documentowindow
Risultato atteso
Ho creato archivioStrumentiFake.js e archivioPrestitiFake.js in test/fakes/.
I fake rispettano il contratto degli adapter reali.
I test di registraPrestito e chiudiPrestito usano i fake e passano senza browser.
Ogni test crea un'istanza nuova del fake — nessuno stato condiviso.
Il prossimo passo sarebbe aggiungere un fake per segnalare guasti.