2012-04-10 9 views
4

Ich habe Methode, die Liste der Dateien vom FTP-Server abruft, wie unten:Ist es möglich, Windows-/Netzwerk-Anmeldeinformationen zu übergeben, die von WebRequest für den Zugriff auf den lokalen Ordner anstelle von Remote-FTP im Komponententest verwendet werden?

public List<string> FetchFilesList() 
    { 
     var request = WebRequest.Create(FtpServerUri); 
     request.Method = WebRequestMethods.Ftp.ListDirectory; 

     request.Credentials = Credentials; 

     using (var response = request.GetResponse()) 
     { 
      var responseStream = response.GetResponseStream(); 

      using (var reader = new StreamReader(responseStream)) 
      { 
       var fileNamesString = reader.ReadToEnd(); 
       var fileNames = fileNamesString.Split(
        Environment.NewLine.ToCharArray(), 
        StringSplitOptions.RemoveEmptyEntries); 

       return fileNames.ToList(); 
      } 
     } 
    } 

Ich versuche, UT zu schreiben, die mein lokales Verzeichnis statt FTP zugreifen würden.

Hier ist mein UT:

// ftpFetcherTestWrapper is thin wrapper to expose properties to UT 
// TODO: For some reason providing credentials like this doesn't work :(
// It also doesn't work for DefaultNetworkCredentials 
ftpFetcherTestWrapper.CredentialsExposed = CredentialCache.DefaultCredentials; 
// As we are using wrapper we substitude FtpServerUri to our fake-local folder 
ftpFetcherTestWrapper.ServerUriExposed = new Uri(directoryName); 

var filesList = ftpSFetcherTestWrapper.FetchFilesList(); 

I System.Net.WebException: "Access to the path 'D:\\SomePathToUnitTestsExecutionFolder\\XmlFiles' is denied."

Q erhalten: Ist es möglich, Fenster/Netzwerk-Anmeldeinformationen übergeben von WebRequest verwendet werden anstelle von FTP in Einheit lokalen Ordner zuzugreifen Prüfung?

[EDIT]

Bitte beachte, dass ich in der Lage Dateiinhalte zu testen, holen, wenn lokale Dateipfad bereitgestellt wird, statt ftp ein:

public XDocument FetchFile(string fileName) 
{ 
    var client = new WebClient(); 
    client.Credentials = Credentials; 

    var fileUri = new Uri(FtpServerUri, fileName); 
    var downloadedXml = client.DownloadString(fileUri); 
    return XDocument.Parse(downloadedXml); 
} 

auch, dass ich bin mir bewusst, Was ich tue, ist keine 100% ige Definition von Unit Test, aber ich denke immer noch, dass dies ein guter Test ist.

+0

Es gibt ein nettes Werkzeug bei github: https://github.com/Buthrakaur/FtpIntegrationTesting/tree/master/FtpIntegrationTesting, aber es führt tatsächlich ftpdmin.exe. Immer noch nicht wirklich was ich will. –

Antwort

1

Wie wäre es, diesen Ordner zu teilen und dann darauf zuzugreifen, wie es ein Netzwerkpfad wäre? I.e. \\ mein-PC-Name \ der-Ordner?

gegoogelt ein bisschen: http://www.velocityreviews.com/forums/t78357-webrequest-and-shared-files.html

WebRequest request = WebRequest.Create("http://localhost/tempasp/temp/trace.txt"); 
request.PreAuthenticate = true; 
request.Credentials = new NetworkCredential("user", "pass", "domain"); 

WebResponse response = request.GetResponse(); 
StreamReader reader = new StreamReader(response.GetResponseStream()); 

string line = String.Empty; 
while ((line = reader.ReadLine()) != null) 
{ 
    Response.Write(line); 
    Response.Write("<BR>"); 
} 
reader.Close(); 
response.Close(); 

ist dies gonna Arbeit für Sie?

+0

Dies funktioniert möglicherweise. Ich möchte jede manuelle Einrichtung vermeiden, die für Komponententests erforderlich ist, z. B. das Freigeben eines Ordners. Ich werde es später überprüfen und Sie wissen lassen, ob es für mich funktioniert. Ich suche immer noch nach weniger schmerzhaften Lösungen. Vielen Dank. –

+0

Sie können den Ordner in Ihren [TestInitialize()] - und [TestCleanup()] - Methoden mithilfe des Codes dieser SO-Frage freigeben/freigeben, z. B. http://stackoverflow.com/questions/1783372/create-shared-folder-accessible -from-domain-with-c-sharp – avs099

+0

Ich war in der Lage, Code aus dieser Antwort (+ einige msdn Hilfe) zu verwenden und es tatsächlich freigegebenen Ordner. Ich habe auch überprüft, dass der Zugriff auf "Jeder" gewährt wurde, aber innerhalb meines Komponententests, wenn ich versuche, auf "// localhost/SharedFolder" zuzugreifen, bekomme ich immer noch denselben Typ von Ausnahme. Vielleicht ist es erwähnenswert, dass der Zugriff auf lokale Dateien für mich in ähnlicher Weise funktioniert, die den Inhalt der Datei abruft. Aber wie Sie in meiner Frage sehen können, möchte ich Anfrage.Methode zu Ftp one. –

2

Das Testen von fetchFilesList() mit seinen Abhängigkeiten (zum Webrequest) wird als Integrationstest bezeichnet. Ich denke, Sie möchten einen Komponententest schreiben, d. H. Testen, dass die fetchFilesList() speziell tut. Sie möchten die WebRequest nicht in einem Komponententest testen. Sie sollten behaupten, dass es tut, was es sollte. Um dies zu erreichen, müssen Sie es einkapseln und verspotten. Ich würde persönlich eine FtpWebRequestFactory erstellen, die WebRequest konfiguriert und zurückgibt.

private FtpWebRequestFactory ftpWebRequestFactory; 

public FtpFetcher(FtpWebRequestFactory ftpWebRequestFactory) { 
    this.ftpWebRequestFactory = ftpWebRequestFactory; 
} 

public List<string> FetchFilesList() 
{ 
    var request = ftpWebRequestFactory.Create(FtpServerUri); 

    using (var response = request.GetResponse()) 
    { 
     var responseStream = response.GetResponseStream(); 

     using (var reader = new StreamReader(responseStream)) 
     { 
      var fileNamesString = reader.ReadToEnd(); 
      var fileNames = fileNamesString.Split(
        Environment.NewLine.ToCharArray(), 
        StringSplitOptions.RemoveEmptyEntries); 

      return fileNames.ToList(); 
     } 
    } 
} 

Jetzt in Ihrem Gerät zu testen, verwenden Sie einen Mock Rahmen (wie moq) ein Modell für die FtpWebRequestFactory zu erstellen. Konfigurieren Sie den Schein, um eine Scheinanforderung zurückzugeben, und konfigurieren Sie diese Scheinanforderung, um eine Scheinantwort zurückzugeben. An diesem Punkt können Sie die Antwort einfach so konfigurieren, dass der richtige Stream zurückgegeben wird.

+0

Vielen Dank für die Antwort. Es macht Sinn. Nicht, dass ich nicht daran gedacht hätte, mehr Abstraktion hinzuzufügen, aber eine, die Sie vorschlagen, sieht elegant aus. Ich frage mich immer noch, ob es einen Weg gibt, um Code auszuführen, den ich auf Ordner habe, weil ich eine ähnliche Methode habe, die Dateiinhalte abruft und innerhalb von UT einwandfrei funktioniert! Also muss es etwas mit der Anfrage geben. –

1

Sie sollten wahrscheinlich die Adresse Scheme (d. H. "Datei") der Uri in der Anfrage hinzufügen. Ansonsten hat .NET keine Ahnung, welches Protokoll für den Zugriff auf die Ressource verwendet werden soll. Da Sie auf die lokale Datei zugreifen, sind Sie in den meisten Fällen bereits autorisiert, sodass Sie keine Anmeldeinformationen festlegen müssen. Bitte versuchen Sie den folgenden Code:

static void Main(string[] args) 
    { 
     Uri uri = new Uri(@"file:///C:\BuddyBuild\x.xml"); 
     FetchFilesList(uri); 
     Console.ReadLine(); 
    } 

    static List<string> FetchFilesList(Uri uri) 
    { 
     var request = WebRequest.Create(uri); 
     request.Method = WebRequestMethods.Ftp.ListDirectory; 
     //request.Credentials = CredentialCache.DefaultCredentials; 

     using (var response = request.GetResponse()) 
     { 
      var responseStream = response.GetResponseStream(); 
      using (var reader = new StreamReader(responseStream)) 
      { 
       var fileNamesString = reader.ReadToEnd(); 
       var fileNames = fileNamesString.Split(
        Environment.NewLine.ToCharArray(), 
        StringSplitOptions.RemoveEmptyEntries); 

       return fileNames.ToList(); 
      } 
     } 
    } 

Hinweis die erste Zeile in Haupt: "file: /// path_to_your_file".

jedoch als Pierre-Henri spitze, das sieht nicht wie ein gutes Design für Unit Test. Welches ist die "Einheit", die Sie testen werden? Der FtpWebRequest Teil oder der Teil, den Sie Dateiinhalt in eine Liste aufteilen? Ich würde stattdessen Ihre FetchFilesList Methode in 2 geteilt:

public static List<String> FetchList(Stream stream) 
    { 
     using (var reader = new StreamReader(stream)) 
     { 
      var fileNamesString = reader.ReadToEnd(); 
      var fileNames = fileNamesString.Split(
       Environment.NewLine.ToCharArray(), 
       StringSplitOptions.RemoveEmptyEntries); 

      return fileNames.ToList(); 
     } 
    } 

    public static List<string> FetchFilesList2(Uri uri) 
    { 
     var request = WebRequest.Create(uri); 
     request.Method = WebRequestMethods.Ftp.ListDirectory; 

     using (var response = request.GetResponse()) 
     { 
      return FetchList(response.GetResponseStream()); 
     } 
    } 

Auf diese Weise können Sie Unit-Tests für das 2-Verfahren separat tun. Especailly, können Sie testen FetchList (Stream-Stream) mit einem beliebigen Stream Objekt, das Sie mögen (FileStream, MemoryStream, Stream von WebResponse, ...).

EDIT: Leider habe ich nicht erkennen, Sie Dateien in einem (lokalen) Verzeichnis, indem Sie den URI in einem lokalen Verzeichnis aufzulisten versuchen. Ich glaube nicht, dass dies mit der WebRequest/Response-Klassenfamilie möglich ist. Wenn der URI-Parameter auf einen lokalen Pfad festgelegt ist, gibt der WebRequest.Create-Aufruf ein FileWebRequest-Objekt zurück, das intern eine FileWebStream für den Zugriff auf die lokale Datei verwendet. FileWebStream erbt FileStream, und es kann nicht für Verzeichnisse verwendet werden. BTW: Wenn Sie den URI-Parameter auf eine FTP-Adresse setzen, gibt der WebRequest.Create-Aufruf stattdessen ein FtpWebRequest-Objekt zurück. Dies ist auch einer der Gründe, warum ich das nicht für einen guten Unit Test halte :). Vielleicht können Sie versuchen, FileWebRequest zu erweitern (FtpWebRequest ist versiegelt), um Verzeichnislistenanfragen zu bearbeiten.

+0

Splitting macht Sinn. Auch hier arbeite ich nicht mit Datei sondern mit Verzeichnis. Ihr Vorschlag mit "file: //" funktioniert nur, wenn ich versuche, Dateiinhalte mit ähnlichen Methoden herunterzuladen. Und ich denke, das ist ein guter Test, auch wenn es nicht zur Definition von UnitTest 100% geeignet ist. –

+0

Leider habe ich nicht bemerkt, dass Sie versuchen, Dateien in einem lokalen Verzeichnis aufzulisten. Die Antwort wurde am Ende des Originals aktualisiert. –

+0

Ihr Update ist sehr gut. Vielen Dank! –