Nella stragrande maggioranza dei linguaggi e dei framework, lo stream è un concetto astratto, e i metodi possono essere progettati per accettare flussi generici (che possono essere sostituiti per dati in memoria) invece di file concreti oggetti di sistema.
Personalmente non ho trovato molto beneficio per le operazioni sui file unit test oltre quel livello, perché ci sono così tante cose che possono andare storte in pratica che i test unitari non provano quasi nulla circa la capacità dell'applicazione di svolgere la sua funzione.
In realtà è molto simile alle astrazioni del database; in genere non si tenta di astrarre qualcosa come la connessione al database o una sessione ORM / contesto / altro, basta creare un'astrazione "repository" o "query" per incapsulare tutto l'accesso ai dati e simulare ciò. Quindi il file I / O non è molto diverso; in genere non si desidera astrarre il file system stesso, ma l'operazione viene eseguita sul file system espressa in termini di dominio del problema e deve essere eseguita nel codice utente.
Se stai scoprendo che devi prendere in giro il file system, direi che il tuo sistema sotto test sta diventando un po 'troppo intimo. È sufficiente delegare le operazioni sui file a una manciata di astrazioni di livello superiore ed escludere le loro implementazioni dalla copertura del codice, come faresti normalmente con le query SQL.