2009-08-11 13 views
19

Prima di tutto, io sono consapevole del fatto che questa domanda è pericolosamente vicino a: How to MapPath in a unit test in C#C# Unità di test: test di un metodo che utilizza MapPath

spero tuttavia, che ha una soluzione diversa. Il mio problema segue:

Nel mio codice ho un oggetto che deve essere convalidato. Sto creando dei test unitari per ogni metodo di convalida per assicurarmi che stia convalidando correttamente. Sto creando dati simulati e caricandolo nell'oggetto, quindi convalidandolo. Il problema è che durante la convalida, quando si verifica un errore, viene assegnato un codice di errore. Questo codice di errore viene utilizzato per raccogliere informazioni sull'errore da un file xml utilizzando Server.MapPath. Tuttavia, quando si tenta di ottenere il file xml, viene generata un'eccezione che significa che il file non può essere trovato.

Poiché MapPath è nel mio codice di convalida e non nel mio test di unità, come faccio a ottenere il mio test dell'unità per riconoscere il percorso? Questa domanda ha senso?

Error Line (Nel mio codice di convalida non la mia prova di unità):

XDocument xdoc = XDocument.Load(HttpContext.Current.Server.MapPath("App_Data/ErrorCodes.xml")); 

semplificata: test di unità chiama un metodo nel mio programma che chiama Server.MapPath che poi fallisce.

risposta

15

Estrarre il "nomefile provider" in una classe che restituisce semplicemente una posizione, quindi è possibile prenderlo in giro molto, molto più facilmente.

public class PathProvider 
{ 
    public virtual string GetPath() 
    { 
     return HttpContext.Current.Server.MapPath("App_Data/ErrorCodes.xml"); 
    } 
} 

Quindi, è possibile utilizzare la classe PathProvider direttamente ...

PathProvider pathProvider = new PathProvider(); 
XDocument xdoc = XDocument.Load(pathProvider.GetPath()); 

o modelli fuori nei test:

PathProvider pathProvider = new MockPathProvider(); // using a mocking framework 
XDocument xdoc = XDocument.Load(pathProvider.GetPath()); 
+2

GetPath() dovrebbe essere virtuale. – dahlbyk

+0

@Dan HttpContext.Current. restituisce null quando eseguiamo da TestProject. Un modo per evitarlo? –

+0

@JibinMathew Sì, non utilizzare 'HttpContext.Current'. So che sembra faceto ma è vero. Generalmente, non prendere in giro classi che non possiedi, ma puoi scrivere una classe wrapper per 'HttpContextBase' che implementa la funzionalità desiderata. –

1

Provare a utilizzare Rhino Mock o un framework di derisione alternativo per deridere l'httpContext (o altri oggetti dipendenti) Oppure è possibile scrivere i propri oggetti fittizi. Oppure scrivi una classe MapPathWrapper, eredita da una classe MapPathWrapperBase per il tuo ambiente reale, quindi per i tuoi test di unità crea un oggetto MockMapPathWrapper.

Ci dovrebbero essere un sacco di esempi per deridere su SO.

Ecco quello che ho chiesto:

How to use Rhino Mocks to Mock an HttpContext.Application

UPDATE Ho esperienza fare questo con l'Asp.Net MVC unica, con webforms ho ImageIN che sarebbe stato molto più difficile a causa della mancanza di una classe HttpContextBase.

1

vorrei estrarre i metodi che accettano le dipendenze come argomenti:

public void Validate(HttpContext context) 
{ 
    ValidatePath(context.Server.MapPath("App_Data/ErrorCodes.xml")); 
} 

public void ValidatePath(string path) 
{ 
    XDocument xdoc = XDocument.Load(path); 
    ValidateDocument(xdoc); 
} 

public void ValidateDocument(XDocument xdoc) 
{ 
    // Original code 
} 

È quindi possibile testare i vari metodi in modo indipendente. Ad esempio, verificare come ValidatePath() gestisce un file mancante.

11

Dopo alcuni controlli rigorosi su google e l'aiuto di un collega abbiamo trovato una soluzione semplice già integrata.net

Sopra i test di unità che accede il processo di convalida, ho aggiunto:

[TestMethod()] 
[HostType("ASP.NET")] 
[UrlToTest("http://localhost:###/upload_file.aspx")] 
[AspNetDevelopmentServerHost("Path To Web Application", "Path To Web Root")] 

Questo funziona perfettamente. Fondamentalmente, quando viene chiamato il test, carica l'URL con il test unitario specificato nel caricamento della pagina. Poiché si tratta di un sito Web che sta chiamando il test dell'unità, la convalida avrà accesso a Server.MapPath. Questa soluzione potrebbe non funzionare per tutti, ma era perfetta per questo. Grazie a tutti voi che avete contribuito

+1

Test di integrazione come questo sono sicuramente utili per assicurarsi che tutti i pezzi lavorino insieme, ma ci sono altri scenari (come un file mancante) che questa soluzione non sarebbe in grado di gestire. Generare l'applicazione web di prova è anche un'operazione piuttosto costosa, che può essere sommata se si eseguono test frequentemente. – dahlbyk

+0

d'accordo, mentre questa soluzione ha qualche merito, nel senso che può fornire informazioni utili quando è in esecuzione, non è un test unitario in alcun senso della parola e non ha più i benefici dei test unitari reali. – kai

+0

è un ottimo risparmio di tempo !! – Luther