2010-07-20 2 views
12

Ho alcune funzioni che leggono i file di modifica &. Al fine di rendere i test unitari indipendenti da qualsiasi problema relativo al file system, voglio includere i file all'interno del progetto.Incluso il file di risorse per il test dell'unità nel progetto C#

Tuttavia, la mia funzione dovrebbe recuperare il filePath e tutto ciò che posso ottenere dall'assembly è FileStream. Qualche idea su come posso ottenere il percorso del file di un file di risorse nel progetto?

System.Reflection.Assembly a = System.Reflection.Assembly.Load(assemblyName); 
FileStream stream = a.GetFile(assemblyName + "." + fileName); 

Grazie!

+1

IMHO tali test-dati non deve mai essere costruito nella prova e dovrebbe essere fornita a parte (che permette anche di eseguire nuovamente il test con dati diversi, senza ricostruzione). Di quale tipo di problemi con il file system sei preoccupato? –

+2

Non mi piace che i test di unità dipendano da risorse esterne, che possono essere modificate, spostate, modificate e così via. Questo test unitario viene eseguito per verificare 1 scenario e voglio che lo scenario esatto sia testato, quindi dovrebbe essere indipendente dal fatto che i permessi dei file possono essere cambiati, troppi gestori di file aperti, disco NTFS non disponibile e così via .. – Yossale

+0

Penso che questa sia una buona domanda. Per quanto riguarda i test di unità reali, ammetto che l'utilizzo dei dati dei file deve essere evitato, ma se si pensa ai test di integrazione (ad esempio sto scrivendo un lettore di file) utilizzando i dati di test "reali" è sensato imho. – anhoppe

risposta

8

La mia solita soluzione per questo problema è che io refactoring il mio programma per aprire il file nel metodo chiamante e quindi passare un flusso invece di passare il nome del file e aprire il file lì.

Per testare questo mi consente di passare un MemoryStream così posso scrivere il mio test di unità senza utilizzare il filesystem. A volte è ancora più semplice controllare se i dati sono stati scritti correttamente ed è decisamente più veloce, soprattutto per un numero maggiore di test. Devi solo ricordare di svuotare il MemoryStream dopo la scrittura poiché .NET non lo fa sempre automaticamente.

esempio da uno dei miei programmi:

public TestSaveAndLoad() 
{ 
    [... create data to save ...] 
    using (MemoryStream targetStream = new MemoryStream()) 
    { 
    target.Save(targetStream); 
    targetStream.Flush(); 
    targetStream.Seek(0, ...); 
    target.Load(targetStream); 
    } 
    [... assert that the loaded data equals the saved data ...] 
} 
+0

Fresco. Non mi piacevano tutti quei flussi che correvano, e questa sembra una buona soluzione. – Yossale

0

Se si imposta l'azione di creazione del file da copiare, è possibile quindi prevedere dove deve essere il file (probabilmente un gruppo di .. \ .. \ .. \ ma ma comunque). Immagino che tu abbia un input sul tuo metodo per il nome del file, quindi dovrebbe funzionare bene.

Proprio come un suggerimento, è possibile astrarre la lettura/modifica effettiva di quel file in un metodo e passare un valore stringa? L'unico motivo per cui lo porto in ballo è che ha l'odore di un test di integrazione (toccando il file system).

4

Una risorsa incorporata non esiste sul file system, quindi non ha alcun percorso di file.

si hanno due opzioni:

  • cambiare l'API del vostro SUT in modo che accetti un flusso anziché soltanto un percorso di file. Questa soluzione è molto preferita.
  • Salvare la risorsa incorporata in un file temporaneo durante il test dell'unità, assicurandosi di eliminarla di nuovo dopo ogni caso di test.

La prima soluzione è un eccellente esempio di come TDD ci spinge verso migliori, API più flessibili.

+0

Ho iniziato con Stream s tutt'intorno, ma mi sentivo come se stessi facendo juggling con molti handler aperti in aria. Ci penserei due volte, comunque. Grazie. – Yossale

+1

È sempre possibile creare metodi sovraccaricati: uno che acquisisce un percorso file, ma in realtà si limita a delegare l'altro a uno stream ... –

1

È possibile impostare i file di dati da copiare nella directory bin al momento della costruzione del progetto, quindi fare riferimento a tali parametri tramite Directory.GetCurrentDirectory() nel test. O anche lasciarli dove sono e semplicemente utilizzare un percorso relativo basato sulla directory corrente.

Meglio, tuttavia, sarebbe meglio ristrutturare il codice per fare affidamento sulla classe Stream, quindi utilizzare una combinazione di mocking e dependency injection per fornire un flusso fittizio con i dati o utilizzare un flusso di memoria, se la simulazione funziona meglio.

+1

Alcuni test runner non hanno la directory bin come directory corrente durante l'esecuzione del test. Utilizzare 'AppDomain.CurrentDomain.BaseDirectory' per ottenere la directory di deployment, non' Directory.GetCurrentDirectory() '. – Sjoerd