2010-07-20 8 views
12

Ich habe einige Funktionen, die lesen & Dateien ändern. Um die Komponententests unabhängig von Dateisystemproblemen durchzuführen, möchte ich die Dateien in das Projekt einbeziehen.Einschließlich Ressourcen-Datei für Unit-Test in C# -Projekt

Allerdings sollte meine Funktion den filePath erhalten, und alles, was ich von der Assembly bekommen kann, ist ein FileStream. Irgendeine Idee, wie ich den Dateipfad einer Ressourcendatei im Projekt bekommen kann?

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

Vielen Dank!

+1

IMHO solche Testdaten sollten niemals in die Test gebaut werden und sollte separat versorgt werden (was auch können Sie den Test mit verschiedenen Daten ohne Wiederaufbau erneut ausführen). Um welche Art von Dateisystemproblemen geht es Ihnen? –

+2

Ich mag es nicht, dass die Komponententests von externen Ressourcen abhängig sind, die geändert, verschoben, geändert usw. werden können. Dieser Komponententest wird durchgeführt, um 1 Szenario zu überprüfen, und ich möchte, dass das genaue Szenario getestet wird, also sollte es unabhängig davon sein, dass die Dateiberechtigungen geändert werden können, zu viele Dateihandler geöffnet, NTFS-Datenträger nicht verfügbar usw. – Yossale

+0

Ich denke, das ist eine sehr gute Frage. Wie bei realen Unit-Tests gebe ich zu, dass die Verwendung von Datei-Daten vermieden werden sollte, aber wenn Sie an Integrationstests denken (z. B. schreibe ich gerade einen Datei-Reader), verwenden 'echte' Testdaten Sinn imho. – anhoppe

Antwort

8

Meine übliche Lösung für dieses Problem ist, dass ich mein Programm umgestalten, um die Datei in der aufrufenden Methode zu öffnen und dann einen Stream zu übergeben, anstatt den Dateinamen zu übergeben und die Datei dort zu öffnen.

Zum Testen erlaubt mir dies, einen MemoryStream zu übergeben, so dass ich meinen Komponententest schreiben kann, ohne das Dateisystem zu benutzen. Es ist manchmal sogar einfacher zu überprüfen, ob die Daten korrekt geschrieben wurden und es ist definitiv schneller, besonders für eine größere Anzahl von Tests. Sie müssen nur daran denken, den MemoryStream nach dem Schreiben zu leeren, da .NET dies nicht immer automatisch erledigt.

Beispiel von einem meiner Programme:

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

Kühl. Ich mochte nicht all diese Ströme, die herumlaufen, und das sieht nach einer guten Lösung aus. – Yossale

0

Wenn Sie die Build-Aktion der Datei zum Kopieren festlegen, können Sie dann vorhersagen, wo die Datei sein soll (wahrscheinlich eine Reihe von .. \ .. \ .. \ 's aber immer noch). Ich nehme an, Sie haben eine Eingabe für Ihre Methode für den Dateinamen, so dass es gut funktionieren sollte.

Wie ein Vorschlag ist es möglich, das tatsächliche Lesen/Ändern dieser Datei in eine Methode zu abstrahieren und einen String-Wert zu übergeben? Der einzige Grund, warum ich das aufbringe, ist, dass es nach einem Integrationstest riecht (Berühren des Dateisystems).

4

Eine eingebettete Ressource existiert nicht im Dateisystem, daher hat sie keinen Dateipfad.

Sie haben zwei Möglichkeiten:

  • Ändern Sie die API Ihrer SUT so, dass es einen Strom statt nur einen Dateipfad akzeptiert. Diese Lösung ist sehr bevorzugt.
  • Speichern Sie die eingebettete Ressource während des Komponententests in einer temporären Datei und stellen Sie sicher, dass sie nach jedem Testfall erneut gelöscht wird.

Die erste Lösung ist ein hervorragendes Beispiel dafür, wie TDD treibt uns in Richtung besser, flexibler APIs.

+0

Ich begann mit Stream s rundherum, aber ich fühlte mich wie ich mit viel offenen Handler in der Luft jonglieren. Ich würde jedoch einen zweiten Gedanken machen. Vielen Dank. – Yossale

+1

Sie können immer überladene Methoden erstellen: eine, die einen Dateipfad akzeptiert, aber nur an die andere delegiert, die einen Stream ... –

1

Sie können die zu kopierenden Datendateien beim Erstellen des Projekts in das bin-Verzeichnis setzen und sie dann in Ihrem Test über Directory.GetCurrentDirectory() referenzieren. Oder lassen Sie sie einfach dort, wo sie sind, und verwenden Sie einfach einen relativen Pfad basierend auf dem aktuellen Verzeichnis.

Besser wäre es jedoch, den Code so zu restrukturieren, dass die Stream-Klasse verwendet wird. Verwenden Sie dann eine Kombination aus Mocking und Abhängigkeitsinjektion, um einen Mock-Stream mit den Daten bereitzustellen - oder verwenden Sie einen Speicherstream, wenn die Fälschung besser funktioniert.

+1

Einige Testläufer haben das bin-Verzeichnis nicht als aktuelles Verzeichnis beim Ausführen des Tests. Verwenden Sie 'AppDomain.CurrentDomain.BaseDirectory', um das Bereitstellungsverzeichnis zu erhalten, nicht' Directory.GetCurrentDirectory() '. – Sjoerd