Unit testing code with a file system dependency

Judah Gabriel Himango picture Judah Gabriel Himango · Sep 24, 2008 · Viewed 45.7k times · Source

I am writing a component that, given a ZIP file, needs to:

  1. Unzip the file.
  2. Find a specific dll among the unzipped files.
  3. Load that dll through reflection and invoke a method on it.

I'd like to unit test this component.

I'm tempted to write code that deals directly with the file system:

void DoIt()
{
   Zip.Unzip(theZipFile, "C:\\foo\\Unzipped");
   System.IO.File myDll = File.Open("C:\\foo\\Unzipped\\SuperSecret.bar");
   myDll.InvokeSomeSpecialMethod();
}

But folks often say, "Don't write unit tests that rely on the file system, database, network, etc."

If I were to write this in a unit-test friendly way, I suppose it would look like this:

void DoIt(IZipper zipper, IFileSystem fileSystem, IDllRunner runner)
{
   string path = zipper.Unzip(theZipFile);
   IFakeFile file = fileSystem.Open(path);
   runner.Run(file);
}

Yay! Now it's testable; I can feed in test doubles (mocks) to the DoIt method. But at what cost? I've now had to define 3 new interfaces just to make this testable. And what, exactly, am I testing? I'm testing that my DoIt function properly interacts with its dependencies. It doesn't test that the zip file was unzipped properly, etc.

It doesn't feel like I'm testing functionality anymore. It feels like I'm just testing class interactions.

My question is this: what's the proper way to unit test something that is dependent on the file system?

edit I'm using .NET, but the concept could apply Java or native code too.

Answer

andreas buykx picture andreas buykx · Nov 2, 2010

Yay! Now it's testable; I can feed in test doubles (mocks) to the DoIt method. But at what cost? I've now had to define 3 new interfaces just to make this testable. And what, exactly, am I testing? I'm testing that my DoIt function properly interacts with its dependencies. It doesn't test that the zip file was unzipped properly, etc.

You have hit the nail right on its head. What you want to test is the logic of your method, not necessarily whether a true file can be addressed. You don´t need to test (in this unit test) whether a file is correctly unzipped, your method takes that for granted. The interfaces are valuable by itself because they provide abstractions that you can program against, rather than implicitly or explicitly relying on one concrete implementation.