modulo 04 / lezione 24

Isolare la causa

Quando il bug è nei dati

Riconoscere input incompleti, duplicati, ordinamenti inattesi, valori limite, NaN, null, stringhe vuote, encoding misti. Collegare al testing classico.

55 minDebugging

In parole semplici

Spesso il codice è giusto. È il dato che è strano. Un null inatteso, un duplicato silente, un ordinamento implicito che non c’è più, una stringa vuota dove ci si aspettava un nome, un NaN che si propaga in una somma: bug invisibili al codice, visibili ai test.

Questa lezione costruisce intuizioni per vedere i dati problematici.

Parole nuove

  • edge case: caso limite del dominio (0, vuoto, max, min, negativo).
  • null/undefined/NaN: rappresentazioni di “assenza” e “non-numero”.
  • boundary value analysis: tecnica di testing che si concentra sui confini.
  • equivalence partitioning: divisione del dominio in classi che si comportano uguale.
  • fixture: dato di prova fissato (introdotto nel modulo 0).

Cosa impari

  • Riconoscere i tipi di dato problematici.
  • Costruire fixture mirate per confini, vuoti, duplicati.
  • Collegare i casi a tecniche classiche del testing (boundary value, equivalence partitioning).

Le otto facce del dato problematico

1. Valori vuoti

[]
""
null
undefined
{}

Esempio: una funzione che calcola la media riceve [] e divide per 0.

function media(nums) {
  return nums.reduce((a, n) => a + n, 0) / nums.length;
}
media([]);  // NaN

2. Valori al confine

Minimo, massimo, e i due vicini. Esempio per età: -1, 0, 1, 17, 18, 19, 120, 121.

3. Duplicati

[1, 1, 2, 3, 3, 3]
[{id: 1}, {id: 1}]

Bug tipici: somma duplicata, deduplicazione mancante, chiave non univoca.

4. Ordinamenti inattesi

Molte API non garantiscono l’ordine. Esempio: Object.keys() di un oggetto può variare nel tempo. Fidarsi dell’ordine è bug latente.

5. NaN e Infinity

0 / 0;        // NaN
1 / 0;        // Infinity
NaN === NaN;  // false (!)
NaN + 1;      // NaN (si propaga)

NaN “infetta” ogni operazione. Una volta entrato, esce dappertutto.

6. Stringhe vuote vs spazi vs null

""           // stringa vuota
" "          // spazio
"\n"         // newline
null
undefined

Una validazione if (nome) salta "" ma lascia passare " ". Una if (nome.trim()) salta entrambi.

7. Encoding misto

UTF-8 + Latin-1 + Windows-1252 mescolati. Una stringa con accenti diventa caff�. Approfondimento nel modulo 8.

8. Date e fusi

2024-12-31T23:00Z in fuso Europe/Rome è 2025-01-01 00:00. Salva con il fuso, dimentica, e i bug fanno saltare il capodanno.

Boundary value analysis

Per ogni intervallo numerico, prova:

  • Il limite inferiore, uno sotto, uno sopra.
  • Il limite superiore, uno sotto, uno sopra.
  • Lo zero (anche se fuori range, è speciale).

Esempio: funzione che accetta età 18-65.

Input Atteso Perché
17 rifiutato sotto il minimo
18 accettato minimo
19 accettato poco sopra
64 accettato poco sotto il massimo
65 accettato massimo
66 rifiutato oltre il massimo
0 rifiutato edge
-1 rifiutato negativo

Equivalence partitioning

Dividi il dominio in classi che si comportano uguale. Testane una per classe + i confini.

Per un campo “codice fiscale italiano”:

  • classe valida: stringa lunga 16, formato corretto.
  • classe invalida (lunghezza): 15 o 17 caratteri.
  • classe invalida (formato): 16 caratteri ma cifre dove vanno lettere.
  • classe vuota: "", null, undefined.

Quattro classi → quattro fixture, più tre per i confini di lunghezza.

Fixture mirate

Per ogni bug nei dati, costruisci tre fixture:

  1. Confine: il valore esatto al limite.
  2. Dominio: un valore nel dominio normale.
  3. Fuori dominio: un valore che la funzione non dovrebbe accettare.

Salva le fixture nel repo come file .json o costanti. Ogni bug futuro che riguarda gli stessi dati ha già la prova pronta.

Esercizio guidato

Prendi una funzione di validazione che hai scritto. Per ogni parametro:

  1. Identifica intervallo o classi di equivalenza.
  2. Scrivi 8 fixture: vuoto, null, sotto confine, confine, dentro, confine superiore, sopra, tipo sbagliato.
  3. Esegui la funzione su ogni fixture. Documenta l’esito.
  4. Le fixture sorprendenti (esito inatteso) sono i tuoi prossimi bug da indagare.

Esempio: la funzione “innocente”

function calcolaIVA(prezzo) {
  return prezzo * 1.22;
}

Sembra impossibile sbagli. Eppure:

  • calcolaIVA(undefined)NaN.
  • calcolaIVA(null)0. Forse non lo vuoi.
  • calcolaIVA("10")12.2. Coercion silenziosa.
  • calcolaIVA(-5)-6.1. Negativo passa.
  • calcolaIVA(1.1)1.342. Numero a virgola mobile, occhio al confronto.

Cinque fixture banali rivelano cinque comportamenti sgraditi.

Errori frequenti del principiante

  • Testare solo l’“happy path”. Il bug vive sempre sui confini.
  • Dare per scontato l’ordinamento. Mai.
  • Confondere null, undefined, "" e 0. Quattro cose diverse.
  • Saltare le date. Le date sono la materia oscura del software.