2012-01-07 13 views
6

Voglio creare il codice testabile dell'unità che prende in giro le chiamate alle classi .Net System.IO, così posso davvero testare l'unità invece che a seconda del filesystem. Sto usando le classi SystemWrapper per fare il giro delle classi BCL.Come creare codice verificabile usando le classi IO .Net?

Sto cercando di ottenere un semplice esempio di funzionamento per vedere se esiste un file.

Il problema che sto avendo è che l'iniezione di dipendenza nella classe non funziona perché istanziare la dipendenza (attraverso StructureMap) richiede sapendo cosa parametro del costruttore passare, che non sarà disponibile in quel momento, v'è anche nessun costruttore predefinito.

codice di esempio:

// don't want to create dependency here like so 
//IFileInfoWrap fileInfoWrap = new FileInfoWrap(filename); 

// using service locator (anti-pattern?!) since it can't be 
// injected in this class 
var fileInfoWrap = ObjectFactory.GetInstance<IFileInfoWrap>(
    new ExplicitArguments(new Dictionary<string, object> 
    { 
     {"fileName", filename} 
    })); 

Console.WriteLine("File exists? {0}", fileInfoWrap.Exists); 

Quello che non mi piace è che la dipendenza non è iniettato, ObjectFactory non dovrebbe essere qui (ma non vedo altro modo per creare questo). ExplicitArguments lo rende caotico e il nome-argomento è una stringa magica.

per me per ottenere questo al lavoro di classe StructureMap config ha bisogno di sapere explict quale costruttore voglio usare (ho appena iniziato con StructureMap quindi questo potrebbe non essere il modo giusto per configurarlo):

ObjectFactory.Initialize(x => 
{ 
    x.Scan(scan => 
    { 
     scan.AssembliesFromPath("."); 
     scan.RegisterConcreteTypesAgainstTheFirstInterface(); 
     scan.WithDefaultConventions(); 
    }); 

    // use the correct constructor (string instead of FileInfo) 
    x.SelectConstructor(() => new FileInfoWrap(null as string)); 

    // setting the value of the constructor 
    x.For<IFileInfoWrap>() 
     .Use<FileInfoWrap>() 
     .Ctor<string>("fileName") 
     .Is(@"."); 
}); 

Qualcuno ha trovato una soluzione migliore per creare codice verificabile contro le classi System.IO? So parte del problema è nella progettazione delle classi System.IO.

+3

SystemWrapper contiene astrazioni per lo più estremamente perde. Sarebbe molto più semplice e più semplice modellare IO in streaming, TextWriter, TextReader, ecc. Queste classi sono già astratte, eliminando completamente la necessità di SystemWrapper. –

+0

Un altro voto per i flussi –

+0

I miei risultati con SystemWrapper sono che sembra essere un buon wrapper con interfacce, tuttavia è ancora un vicolo cieco a causa del modo in cui funzionano le classi originali. Ad esempio, la restituzione di un array di oggetti FileInfo non può essere corretta in modo corretto. Rotolando il mio involucro più semplificato che non deve imitare le classi esistenti, mentre più lavoro porta a una soluzione praticabile IMHO. –

risposta

5

Un approccio che ho utilizzato con molto successo è il rollover dei miei tipi di proxy per i tipi trovati in System.IO e in altre parti della FCL. Per esempio. Voglio prendere una dipendenza su System.IO.File. Creo una libreria denominata System.IO.Proxies e aggiungo un tipo concreto File e un'interfaccia IFile. L'interfaccia IFile espone membri equivalenti a tutti quelli che richiedono da System.IO.File e il tipo concreto implementa tali membri facendo nient'altro che le chiamate del metodo di inoltro a System.IO.File. System.IO.Proxies è escluso dalla verifica dell'unità e dalla copertura del codice. Nella mia assemblea consumante, prendo un dipendente solo su System.IO.Proxies e, in particolare, prendo solo una dipendenza su IFile. In questo modo posso prendere facilmente in giro questa dipendenza e raggiungere una copertura del 100% del codice per il mio assemblaggio.

(Si noti che questa è una versione su misura del mio more general answer ad una domanda precedente.)

+0

Sì, questo è anche il modo in cui sono finito. Si potrebbe delegare la chiamata a es. System.IO.FileInfo in una classe separata. Il rolling del proprio proxy richiede la creazione di proxy per ogni classe che potrebbe essere un po 'di lavoro, ovviamente può crescere insieme con le funzionalità necessarie dalla classe BCL. Anche quando vengono restituiti altri tipi (FileInfo), tutti gli attributi richiesti devono essere creati nel proxy (Nome, Nome completo, Lunghezza). Si potrebbe pensare che questo problema venga "risolto" già evitando il proxy per tutti. –

+0

Utilizzato lo stesso approccio abbastanza con successo. Di solito non hai bisogno di tutti i metodi/proprietà/eventi di una classe come _File_. E per la manciata di cui hai bisogno è davvero facile scrivere tali wrapper. –

Problemi correlati