2010-08-01 17 views
19

Ich weiß, dass es dringend empfohlen wird, Komponententests in Trennung vom Dateisystem auszuführen, denn wenn Sie in Ihrem Test Dateisystem berühren, testen Sie auch das Dateisystem selbst. OK, das ist vernünftig.
Meine Frage ist, wenn ich Dateispeicherung auf der Festplatte testen möchte, was mache ich? Wie bei der Datenbank, separiere ich eine Schnittstelle, die für den Datenbankzugriff zuständig ist, und erstelle dann eine andere Implementierung für meine Tests? Oder vielleicht gibt es einen anderen Weg?Wie kann ich die Sicherungsdatei auf dem Datenträger testen?

+1

Erstellen Sie eine Schnittstelle für den Zugriff auf das Dateisystem. Dann erstellen Sie seine Spott, entweder mit einem spöttischen Rahmen oder by-Hand. –

+0

vielen Dank für nützliche Kommentare und Antworten, ich denke, ich werde bei der Mocking Framework bleiben – chester89

+0

Unit-Test verwenden keine Systeme. Es sind keine Integrationstests. Komponententest testet nicht die letzte Ebene, die Datei auf Festplatte speichert. Sie benötigen Integrationstests, um die Datei zu speichern. Und in diesem Fall speichern Sie es einfach und überprüfen Sie dann, dass es erstellt wurde. Es ist eine andere Art von Test, verschiedene Ansätze und andere Geschichte. Die meisten der folgenden Antworten sind falsch, während sie über Unit-Tests sprechen, aber versuchen, Integration Tests Practices –

Antwort

36

Mein Ansatz dazu ist stark auf das Growing Object-Oriented Software Guided by Tests (GOOS) Buch, das ich gerade gelesen habe, aber es ist das Beste, was ich heute weiß, voreingenommen. Speziell:

  • Erstellen Sie eine Schnittstelle, um das Dateisystem von Ihrem Code wegzuspalten. Verspotten Sie es, wo diese Klasse als Kollaborateur/Abhängigkeit benötigt wird. Dies hält Ihre Komponententests schnell und schnell.
  • Erstellen Sie Integrationstests, die die tatsächliche Implementierung der Schnittstelle testen. Überprüfen Sie also, ob der Aufruf von Save() tatsächlich eine Datei auf Platte speichert und den Inhalt enthält (verwenden Sie eine Referenzdatei oder analysieren Sie sie für einige Dinge, die sie enthalten sollte)
  • Erstellen Sie einen Abnahmetest, der das gesamte System testet Ende. Hier können Sie einfach überprüfen, ob eine Datei erstellt wurde. Die Absicht dieses Tests besteht darin, zu bestätigen, ob die tatsächliche Implementierung korrekt verkabelt ist.

Update für Kommentator:

Wenn Sie strukturierte Daten gerade lesen (zB Buchobjekte) (Falls nicht Ersatz-String für IEnumerable)

interface BookRepository 
{ 
    IEnumerable<Books> LoadFrom(string filePath); 
    void SaveTo(string filePath, IEnumerable<Books> books); 
} 

Jetzt können Sie verwenden constructor- Injektion, um einen Schein in die Client-Klasse zu injizieren. Die Client-Klasse Komponententests sind daher schnell; nicht das Dateisystem treffen. Sie überprüfen nur, dass die richtigen Methoden auf die Abhängigkeiten (zB Laden/Speichern)

var testSubject = new Client(new Mock<BookRepository>.Object); 

Weiter Sie die reale Umsetzung der BookRepository erstellen müssen genannt werden, die eine Datei (oder eine SQL-DB morgen funktioniert ab, wenn Sie es wollen). Niemand muss es wissen. Schreiben Sie Integrationstests für FileBasedBookRepository (die die oben genannte Rolle implementiert) und testen, dass Aufruf Load mit einer Referenzdatei die richtigen Objekte und Aufruf Save mit einer bekannten Liste, hält sie auf der Festplatte. d. h. verwendet echte Dateien Diese Tests würden langsam sein, also markieren Sie sie mit einem Tag oder verschieben Sie sie in eine separate Suite.

[TestFixture] 
[Category("Integration - Slow")] 
public class FileBasedBookRepository 
{ 
    [Test] 
    public void CanLoadBooksFromFileOnDisk() {...} 
    [Test] 
    public void CanWriteBooksToFileOnDisk() {...} 
} 

Schließlich sollte es ein/mehrere Abnahmen sein, Laden und Speichern ausübt.

+0

Nur neugierig, was ist das GOOS-Buch? Konnte es nicht herausfinden. – Mathias

+0

@Mathias - http://www.growing-object-oriented-software.com/ – Gishu

+1

Wenn es nicht zu viel verlangt ist. Glauben Sie, dass Sie einige Codes für Punkt 1 und 2 bereitstellen können? Ich würde es sehr schätzen. –

6

Sie könnten anstelle eines Dateinamens an Ihre Speicherfunktion einen Stream, TextWriter oder ähnliches übergeben. Dann können Sie beim Testen eine speicherbasierte Implementierung übergeben und überprüfen, ob die richtigen Bytes geschrieben wurden, ohne tatsächlich etwas auf die Festplatte zu schreiben.

Um Probleme und Ausnahmen zu testen, könnten Sie sich ein spöttisches Framework ansehen. Dies kann Ihnen helfen, eine bestimmte Ausnahme zu einem bestimmten Zeitpunkt im Speichervorgang künstlich zu generieren und zu testen, ob Ihr Code dies richtig verarbeitet.

+1

Ich frage mich, ob @ Chester89 auch Tests mit 'ungültigen Pfad', 'Dateikollision', 'gesperrten Datei',' ungültigen Dateinamen' behandelt werden soll , 'save interruption' usw. Ich nehme an, alle diese könnten auch nachgeahmt werden. – scunliffe

+0

@scunliffe, ja, ich möchte diese Dinge auch testen. Wie kann ich dieses Verhalten nachahmen? – chester89

+0

@chester: Sie könnten einen spöttischen Rahmen betrachten. Dies kann Ihnen helfen, diese Ausnahmen zu den entsprechenden Zeiten zu generieren. Denken Sie sorgfältig darüber nach, bevor Sie den Weg zum Testen jeder einzelnen möglichen Fehlerbedingung einschlagen und 100% ige Codeabdeckung von Tests haben. Das ist oft teurer als es wert ist. –

2

Es gibt eine allgemeine Regel, die beim Schreiben von Komponententests, die Datei-E/A durchführen, vorsichtig ist, weil sie dazu neigen, zu langsam zu sein. Aber es gibt kein absolutes Verbot für Datei-E/A in Komponententests.

In Ihren Unit-Tests wird ein temporäres Verzeichnis eingerichtet und abgerissen und Testdateien und Verzeichnisse in diesem temporären Verzeichnis erstellt. Ja, Ihre Tests sind langsamer als reine CPU-Tests, aber sie werden trotzdem schnell sein. JUnit hat sogar Support-Code, um mit genau diesem Szenario zu helfen: a @Rule auf einem TemporaryFolder.

Das heißt, nimmt die meisten Datei das Schreiben von Code dieses Formular:

  1. Öffnen, um die Datei einen Ausgangsstrom. Dieser Code muss mit fehlenden Dateien oder Dateiberechtigungen umgehen. Sie sollten testen, ob die Datei geöffnet wird und mit diesen Fehlerbedingungen fertig wird.
  2. In den Ausgabestream schreiben. Dies muss in dem korrekten Format geschrieben werden, welches der komplizierteste Teil ist, der am meisten getestet werden muss. Es muss beim Schreiben in den Ausgabestrom mit einem E/A-Fehler umgehen, obwohl diese Fehler in der Praxis selten sind.
  3. Schließen Sie den Ausgabestrom. Dies muss beim Schließen des Streams mit einem E/A-Fehler umgehen, obwohl diese Fehler in der Praxis selten sind.

Nur das erste befasst sich wirklich mit dem Dateisystem. Der Rest verwendet nur einen Ausgabestream.

So können Sie den mittleren und letzten Teil zu einer eigenen Methode (Funktion), die einen bestimmten Ausgabestrom statt einer benannten Datei manipuliert. Sie können diesen Ausgabestream dann als Einheit testen, um die Methode zu testen. Diese Komponententests werden sehr schnell sein. Die meisten Programmiersprachen bieten bereits eine geeignete Ausgabestream-Klasse.

Damit bleibt nur der erste Teil der Einheit getestet werden. Sie werden nur ein paar Tests benötigen, so dass Ihre Testsuite immer noch akzeptabel schnell sein sollte.

+0

Siehe auch http://stackoverflow.com/questions/225073/testing-whats-written-to-a-java-outputstream – Raedwald

Verwandte Themen