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.
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:
- Confine: il valore esatto al limite.
- Dominio: un valore nel dominio normale.
- 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:
- Identifica intervallo o classi di equivalenza.
- Scrivi 8 fixture: vuoto, null, sotto confine, confine, dentro, confine superiore, sopra, tipo sbagliato.
- Esegui la funzione su ogni fixture. Documenta l’esito.
- 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,""e0. Quattro cose diverse. - Saltare le date. Le date sono la materia oscura del software.