Gestione Test Data — Cheat Sheet

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.

Concetti chiave

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.

Domande tipiche e risposte pronte

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.

Insidie e errori comuni

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.

Snippet e comandiTypeScript

// 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' });

Da ripassare

[ ] 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

Jarvis Interviews
Jarvis