Dowemo
0 0 0 0


Question:

I know that it's strongly recommended to run unit-tests in separation from file system, because if you do touch file system in your test, you also test file system itself. OK, that's reasonable.
My question is, if I want to test file saving to the disk, what do I do? As with database, I separate an interface that is responsible for database access, and then create another implementation of this for my tests? Or may be there's some other way?


Best Answer:


My approach towards this is heavily biased on the Growing Object-Oriented Software Guided by Tests (GOOS) book that I just read, but it's the best that I know of today. Specifically:

  • Create an interface to abstract away the file system from your code. Mock it where this class is needed as a collaborator/dependency. This keeps your unit-tests quick and feedback fast.
  • Create integration tests that test the actual implementation of the interface. i.e. verify that calling Save() actually persists a file to disk and has the write contents (use a reference file or parse it for a few things that it should contain)
  • Create an acceptance test that tests the whole system - end to end. Here you may just verify that a file is created - the intent of this test is to confirm if the real implementation is wired / plugged in correctly.

Update for commenter:

If you're reading structured data (e.g. Book objects) (If not substitute string for IEnumerable)

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

Now you can use constructor-injection to inject a mock into the client class. The client class unit tests therefore are fast ; do not hit the filesystem. They just verify that the right methods are called on the dependencies (e.g. Load/Save)

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

Next you need to create the real implementation of BookRepository that works off a File (or a Sql DB tommorrow if you want it). No one else has to know. Write integration tests for FileBasedBookRepository (that implements the above Role) and test that calling Load with a reference file gives the right objects and calling Save with a known list, persists them to the disk. i.e. uses real files These tests would be slow so mark them up with a tag or move it to a separate suite.

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

Finally there should be one/more acceptance tests that exercises Load and Save.




Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs