2009-08-05 9 views
14

Ich möchte eine externe XML-Datei in einem Komponententest laden, um einige Verarbeitungscode für dieses XML zu testen. Wie bekomme ich den Pfad der Datei?Wie MapPath in einem Komponententest in C#

die Regel in einer Web-Anwendung würde ich tun:

XDocument.Load(Server.MapPath("/myFile.xml")); 

Aber offensichtlich in meinem Unit-Test habe ich keinen Hinweis auf Server oder Httpcontext so wie kann ich einen Weg Karte, so dass ich nicht angeben muß der vollständige Weg?

UPDATE:

Ich möchte nur klarstellen, dass der Code teste ich eigentlich für einen XML-Parser-Klasse ist, so etwas wie:

public static class CustomerXmlParser { 
    public static Customer ParseXml(XDocument xdoc) { 
    //... 
    } 
} 

So dies zu testen ich brauche ein gültiges XDocument analysieren. Die zu testende Methode greift nicht auf das Dateisystem selbst zu. Ich könnte das XDocument aus einem String direkt im Testcode erstellen, aber ich dachte, es wäre einfacher, es einfach aus einer Datei zu laden.

Antwort

24

Eine andere Idee wäre die Verwendung von Abhängigkeit injecti auf.

public interface IPathMapper { 
string MapPath(string relativePath); 
} 

Und dann einfach 2-Implementierungen verwenden

public class ServerPathMapper : IPathMapper { 
    public string MapPath(string relativePath){ 
      return HttpContext.Current.Server.MapPath(relativePath); 
    } 
} 

Und dann auch Sie benötigen, um Ihre Mock Implementierung

public class DummyPathMapper : IPathMapper { 
    public string MapPath(string relativePath){ 
     return "C:/Basedir/" + relativePath; 
    } 
} 

Und dann werden alle Ihre Funktionen, die Pfad der zur Karte benötigt würde einfach haben müssen Zugriff auf eine Instanz von IPathMapper - in Ihrer Web-App muss es sich um den ServerPathMapper handeln und in Ihrem Gerät wird der DummyPathMapper - basic DI (Dependency Injection) getestet.

+0

Was ist der Vorteil von Interface hier ?. Können wir einfach 2 Klassendateien erstellen und sie entsprechend 1 von einer tatsächlichen App und 1 vom Testendpunkt aufrufen? Kann jemand bitte den Nutzen dieser Schnittstelle hier erklären? –

+0

Durch die Verwendung von Klassen müssen Sie sich entscheiden, dass eine Klasse von der anderen erbt, um das Typsystem glücklich zu machen. Entweder Ihre Testimplementierung erbt von der echten oder umgekehrt ist nicht wirklich eine ideale Lösung. Auf diese Weise müssen Sie Ihre realen und Test-Implementierungen überhaupt nicht voneinander unterscheiden - sie haben nur eine gemeinsame Schnittstelle, die sie erfüllen müssen. – kastermester

5

Persönlich würde ich sehr vorsichtig sein über Code, der auf einem Back-End- Ressource-Speicher, sei es ein Dateisystem oder eine Datenbank - Sie führen eine Abhängigkeit in Ihre Unit-Test, die wahrscheinlich führen wird zu falsch negativen Ergebnissen, dh Tests, die nicht aufgrund Ihres spezifischen Testcodes fehlschlagen, sondern weil die Datei nicht da ist oder der Server nicht verfügbar ist usw. link Für IMO eine gute Definition dessen, was ein Komponententest ist und was noch wichtiger ist, ist nicht

Ihr Komponententest sollte eine atomare, wohldefinierte Funktionalität testen, die nicht testet, ob eine Datei geladen werden kann. Eine Lösung ist es, die Datei laden zu "verspotten" - es gibt verschiedene Ansätze zu diesem jedoch würde ich persönlich nur die Schnittstelle zu dem Dateisystem verspotten, die Sie verwenden und nicht versuchen, ein vollständiges Dateisystem spöttisch - here's eine gute SO Post und here's eine gute sO Diskussion über Dateisystem spöttisch

Hoffnung, die

+0

Nur klar zu sein, teste ich nicht, ob das XML geladen werden kann, oder den Inhalt der Datei zu testen, teste ich ein Stück Code, der ein XDocument benötigt, um analysiert zu werden. Die Datei befindet sich mit den Tests, wenn sie nicht geladen wird, dann zeigt der Test einen Fehler und kein falsches Negativ. Mir ist klar, dass das nicht ideal ist, aber ich weiß es nicht anders. Ich habe meine Frage aktualisiert. –

+0

Natürlich ist das der Punkt, aber nicht wahr? Ihr Code testet Ihren Parser so, dass er die XML-Daten von irrelevant erhält und nicht fehlschlagen sollte, weil die Datei nicht existiert. Persönlich würde ich mit der Zeichenfolge-Option gehen, oder Sie könnten es als eine eingebettete Ressource haben – zebrabox

3

Regel für Unit-Tests hilft ich die xML-Dateien als eingebettete Ressourcen in das Projekt ein und laden sie ein Verfahren wie folgt aus:

public static string LoadResource(string name) 
{ 
    Type thisType = MethodBase.GetCurrentMethod().DeclaringType; 
    string fullName = thisType.Namespace + "." + name + ".xml"; 

    using (Stream stream = thisType.Module.Assembly.GetManifestResourceStream(fullName)) 
    { 
     if(stream==null) 
     { 
     throw new ArgumentException("Resource "+name+" not found."); 
     } 

     StreamReader sr = new StreamReader(stream); 
     return sr.ReadToEnd(); 
    } 
} 
2

Edit: Ich fange von Grund auf neu an, da ich vermute, dass ich Ihre Frage zunächst falsch interpretiert habe.

Die beste Möglichkeit, eine XML-Datei in Ihren Komponententest zu laden, um sie dann in einige Ihrer Klassen zu injizieren, besteht darin, das Attribut DeploymentItem in MS-Komponententests zu verwenden.

Dies wird wie folgt aussehen:

[TestMethod] 
[DeploymentItem(@"DataXmlFiles\MyTestFile.xml", "DataFiles")] 
public void LoadXMLFileTest() 
{ 
    //instead of "object" use your returning type (i.e. string, XDocument or whatever) 
    //LoadXmlFile could be a method in the unit test that actually loads an XML file from the File system 
    object myLoadedFile = LoadXmlFile(Path.Combine(TestContext.TestDeploymentDir, "DataFiles\\MyTestFile.xml")); 

    //do some unit test assertions to verify the outcome 
} 

teste ich nicht den Code jetzt auf einem Debugger, aber es sollte funktionieren.

Edit: Btw, wenn Sie DeploymentItem betrachten diesen Beitrag here verwenden.

1

Klassen:

internal class FakeHttpContext : HttpContextBase 
{ 
    public override HttpRequestBase Request { get { return new FakeHttpRequest(); } } 
} 

internal class FakeHttpRequest : HttpRequestBase 
{ 
    public override string MapPath(string virtualPath) 
    { 
     return /* your mock */ 
    } 
} 

Verbrauch:

[TestMethod] 
public void TestMethod() 
{ 
    var context = new FakeHttpContext(); 
    string pathToFile = context.Request.MapPath("~/static/all.js"); 
} 
Verwandte Themen