Tag: testing, test-data, fixtures, factories, databases, mocking, automation
Livello: intermedio
TL;DR: Strategie per generare, isolare e pulire i dati di test tra unit, integration ed E2E evitando flaky test e collisioni.
Isolamento dello stato: ogni test deve preparare i propri dati e ripulirli al termine.
Fixture statiche vs Object Mother/Factory: preferire factory dinamiche per evitare accoppiamenti rigidi.
Test Data Builder pattern: permette di definire valori predefiniti e sovrascrivere solo i campi rilevanti.
Transazioni atomiche nei test di integrazione: eseguire rollback a fine test per ripristinare il database velocemente.
Troncamento o cleanup esplicito: svuotare le tabelle modificate quando il rollback transazionale non è supportato.
Dati sintetici vs dati anonimizzati: usare generatori (faker) per sviluppo locale e dump anonimizzati per staging.
Gestione univocità: usare contatori sequenziali o UUID dinamici per vincoli di unicità (email, slug, codici).
Determinismo: evitare generatori completamente casuali privi di seed riproducibile per facilitare il debug.
Q: Come eviti la concorrenza tra test che leggono e scrivono sullo stesso database?R: Isolo l'ambiente usando un database o schema dedicato per ogni worker di test, oppure incapsulo ogni suite in transazioni con rollback immediato.
Q: Qual è il vantaggio di usare Factory rispetto a fixture JSON statiche?R: Le factory generano dati validi con valori di default intelligenti, riducono il boilerplate e non si rompono quando lo schema cambia lievemente.
Q: Come tratti i dati di produzione per i test di collaudo e staging?R: Applico pipeline di anonimizzazione o mascheramento prima del dump per eliminare PII, password e riferimenti sensibili nel rispetto del GDPR.
Condivisione dello stato globale: un test modifica un record condiviso e fa fallire i successivi in modo non deterministico.
Hardcoding di ID incrementali: fare assunzioni su ID specifici (es. id = 1) genera fallimenti casuali nei test concorrenti.
Cleanup incompleto: non gestire la pulizia in blocchi finally o teardown, lasciando record orfani dopo errori imprevisti.
Test lenti causati da rigenerazione totale del database ad ogni singolo caso di test invece di applicare pulizia mirata.
// Esempio: Test Data Builder con override mirati
export interface User {
id: string;
email: string;
role: 'admin' | 'user';
isActive: boolean;
}
let seq = 0;
export const buildUser = (overrides: Partial<User> = {}): User => {
seq += 1;
return {
id: `usr_${seq}`,
email: `test-${seq}@example.com`,
role: 'user',
isActive: true,
...overrides,
};
};
// Utilizzo nel test
const admin = buildUser({ role: 'admin' });
[ ] Implementazione del pattern Test Data Builder in TypeScript
[ ] Strategie di transazione/rollback per test di integrazione con database relazionali
[ ] Mascheramento dati PII per ambienti non produttivi
[x] Utilizzo di librerie per dati fittizi e factory dinamiche