modulo 13 di 24 / Ore 21-40

Moduli 9-16 / Checkpoint 40 ore

Stub: risposta controllata per uno scenario

Cos'è uno stub (distinto da mock e fake), come si costruisce uno stub per archivioStrumenti nel Registro con risposta fissa per uno scenario specifico, e quando usare stub rispetto alle altre alternative.

25 min Architettura del software

Stub: risposta controllata per uno scenario

Questa lezione appartiene al Modulo 13 — Testare l’architettura.

Quando vuoi testare registraPrestito senza toccare localStorage, devi sostituire l’archivio con qualcosa di controllato. Uno stub è la scelta più semplice: restituisce sempre la stessa risposta predefinita per uno scenario specifico. Non verifica se viene chiamato, non registra le chiamate: risponde e basta.

Obiettivo della lezione

In questa lezione impari a distinguere uno stub da un mock e da un fake, a costruire uno stub concreto per archivioStrumenti nel Registro, e a capire in quale scenario uno stub è la scelta giusta.

Alla fine devi avere un risultato verificabile: uno stub che restituisce uno strumento guasto, usato in un test di registraPrestito che verifica il rifiuto del prestito.

Le tre alternative: stub, fake, mock

Prima di costruire uno stub, chiarisci la differenza tra i tre tipi di sostituto:

STUB
  Restituisce una risposta fissa per uno scenario specifico.
  Non verifica nulla. Non registra nulla.
  Uso: vuoi controllare l'input di un caso d'uso.
  Esempio: trova() restituisce sempre uno strumento guasto.

FAKE
  Ha un'implementazione reale ma semplificata.
  Funziona davvero, ma in memoria invece che in localStorage.
  Uso: vuoi testare più scenari senza la complessità della persistenza.
  Esempio: archivioStrumentiInMemoria con un array.

MOCK
  Verifica le chiamate: quante volte è stato chiamato, con quali argomenti.
  Uso: vuoi verificare che il caso d'uso chiami i collaboratori nel modo giusto.
  Esempio: verifica che salva() venga chiamato esattamente una volta.

Per questa lezione ci concentriamo sullo stub. È il più semplice e spesso quello di cui hai bisogno quando vuoi isolare un caso limite specifico.

Quando usare uno stub

Usa uno stub quando:

  • vuoi testare che registraPrestito lanci l’errore corretto per uno strumento guasto, senza dover inserire quello strumento in localStorage;
  • hai uno scenario molto specifico che sarebbe difficile riprodurre con un archivio in memoria reale;
  • il test deve essere veloce e leggibile: lo stub dice esattamente qual è lo scenario senza setup complesso.

Non usare uno stub quando:

  • hai bisogno di testare più scenari diversi con lo stesso archivio — usa un fake;
  • vuoi verificare che l’archivio venga chiamato un certo numero di volte — usa un mock;
  • il comportamento dell’archivio è parte essenziale di ciò che stai testando.

Procedura guidata

  1. Identifica lo scenario che vuoi testare: uno strumento guasto che non può essere prestato.
  2. Scrivi lo stub: un oggetto con il metodo trova che restituisce sempre uno strumento guasto.
  3. Scrivi il test che usa lo stub: chiama registraPrestito con l’ID dello strumento guasto.
  4. Verifica che il test lanci l’errore corretto.
  5. Esegui il test e confermane il successo.
  6. Controlla che lo stub non abbia metodi che non usa il test — deve essere minimale.
  7. Aggiungi un commento che spiega perché hai scelto uno stub invece di un fake per questo scenario.

Attività in classe

Compila questa scheda prima di scrivere il codice:

## Stub per archivioStrumenti

Scenario da testare:
  _______________

Metodi dell'archivio usati dal caso d'uso in questo scenario:
  _______________

Risposta fissa che lo stub deve restituire:
  {
    id: "_______________",
    nome: "_______________",
    stato: "_______________"
  }

Errore che il caso d'uso deve lanciare:
  _______________

Perché stub e non fake per questo scenario:
  _______________

Se lavori in gruppo, una persona scrive lo stub e un’altra scrive il test che lo usa.

Spiegazione guidata per studiare

Uno stub risolve un problema preciso: isolare il comportamento del codice che stai testando dalla complessità di ciò che chiama.

registraPrestito chiama archivioStrumenti.trova(id). Nel test, non vuoi che quella chiamata vada a leggere localStorage. Vuoi controllare cosa restituisce, così puoi testare ogni scenario in modo indipendente.

Lo stub più semplice è un oggetto letterale con i metodi che ti servono. Niente classi, niente extends, niente framework. Solo un oggetto che quando chiami trova() restituisce esattamente ciò che hai deciso per quel test.

La differenza con un fake è sottile ma importante. Un fake ha un’implementazione funzionante: puoi chiamarlo trova() con ID diversi e ricevere risposte diverse. Uno stub ha una risposta fissa: sempre quello strumento, sempre quello stato. È più limitato, ma è anche più esplicito — il test dice chiaramente qual è lo scenario che sta verificando.

La differenza con un mock è più netta. Un mock non si limita a rispondere: conta le chiamate e verifica che il codice si comporti in modo specifico. Uno stub non verifica nulla: lascia che sia l’asserzione del test a farlo.

Quando studi, costruisci uno stub a mano per ogni scenario che vuoi testare: strumento disponibile, strumento guasto, strumento in prestito, strumento inesistente. Ogni stub è un test isolato e leggibile.

Passo per passo nel progetto

  1. Apri application/registraPrestito.js e individua ogni chiamata a archivioStrumenti.
  2. Per lo scenario “strumento guasto”, identifica il metodo che viene chiamato: trova(id).
  3. Crea un oggetto stub con solo quel metodo, che restituisce { id: 'id-1', nome: 'Trapano', stato: 'guasto' }.
  4. Scrivi il test: chiama registraPrestito('id-1', 'Mario Rossi') usando lo stub.
  5. Verifica che venga lanciato Error('Lo strumento non è disponibile per il prestito').
  6. Nota che lo stub non ha il metodo salva: non serve per questo scenario, quindi non si mette.
  7. Ripeti il processo per lo scenario “strumento non trovato”: lo stub restituisce null.

Esempio da leggere lentamente

Questo esempio mostra uno stub minimale per due scenari distinti:

// test/registraPrestito.test.js

// Scenario 1: strumento guasto
const archivioStrumentoGuasto = {
  trova(id) {
    // risposta fissa: sempre questo strumento guasto
    return { id: 'id-trapano', nome: 'Trapano Bosch', stato: 'guasto' };
  }
  // nessun altro metodo: questo scenario non arriva mai a salva()
};

function testRifiutaStrumentoGuasto() {
  let erroreRicevuto = null;
  try {
    registraPrestito('id-trapano', 'Mario Rossi', archivioStrumentoGuasto);
  } catch (e) {
    erroreRicevuto = e;
  }
  if (!erroreRicevuto) throw new Error('Il test doveva lanciare un errore');
  if (!erroreRicevuto.message.includes('non è disponibile')) {
    throw new Error('Messaggio di errore non corretto: ' + erroreRicevuto.message);
  }
  console.log('OK — strumento guasto rifiutato correttamente');
}

// Scenario 2: strumento non trovato
const archivioStrumentoInesistente = {
  trova(id) {
    return null; // nessuno strumento con quell'ID
  }
};

function testRifiutaStrumentoInesistente() {
  let erroreRicevuto = null;
  try {
    registraPrestito('id-inesistente', 'Mario Rossi', archivioStrumentoInesistente);
  } catch (e) {
    erroreRicevuto = e;
  }
  if (!erroreRicevuto) throw new Error('Il test doveva lanciare un errore');
  if (!erroreRicevuto.message.includes('non trovato')) {
    throw new Error('Messaggio di errore non corretto: ' + erroreRicevuto.message);
  }
  console.log('OK — strumento inesistente rifiutato correttamente');
}

Nota: ogni stub è un oggetto diverso, con una risposta diversa per uno scenario diverso. Nessun framework, nessuna libreria.

Prova di comprensione

Prima di chiudere la lezione, rispondi per iscritto a queste domande:

  • Qual è la differenza principale tra uno stub e un fake nel Registro?
  • Perché lo stub per “strumento guasto” non ha il metodo salva?
  • In quale scenario sceglieresti un fake invece di uno stub?
  • Come si chiama il pattern di passare l’archivio come parametro invece di importarlo direttamente?

Una risposta accettabile usa i nomi reali delle funzioni e dei file del progetto.

Errori da evitare

  • costruire uno stub con tutti i metodi dell’archivio quando il test ne usa solo uno — lo stub deve essere minimale;
  • usare uno stub per testare il comportamento dell’archivio stesso — uno stub è per testare il codice che chiama l’archivio;
  • confondere stub con mock: uno stub non verifica le chiamate, un mock sì;
  • importare localStorage dentro il test — il punto dello stub è eliminare quella dipendenza;
  • non passare l’archivio come parametro a registraPrestito: se l’archivio è hardcoded nell’importazione, non puoi sostituirlo con uno stub.

Prodotto da consegnare

Scrivi due test che usano due stub distinti:

  • uno stub per lo scenario “strumento guasto” che verifica il rifiuto del prestito;
  • uno stub per lo scenario “strumento non trovato” che verifica il messaggio di errore corretto.

I test devono girare con node test/registraPrestito.test.js senza browser e senza localStorage.

Checklist di chiusura

Prima di chiudere la lezione, controlla:

  • sai spiegare la differenza tra stub, fake e mock con un esempio del Registro;
  • hai scritto uno stub per lo scenario “strumento guasto”;
  • il test con lo stub passa senza toccare localStorage;
  • lo stub ha solo i metodi usati in quello scenario;
  • sai quando sceglieresti un fake invece di uno stub.

Risultato atteso

Alla fine lo studente deve saper dire:

Uno stub è un oggetto con risposta fissa per uno scenario specifico.
Per testare che registraPrestito rifiuti uno strumento guasto,
ho creato uno stub il cui metodo trova() restituisce sempre { stato: 'guasto' }.
Lo stub non ha il metodo salva() perché quel scenario non arriva mai al salvataggio.
La differenza con un fake è che il fake funziona davvero (in memoria), lo stub risponde e basta.

Se questa spiegazione non è possibile, la lezione non è ancora davvero conclusa.