views:

1735

answers:

10

Are there any libraries or methods to mock out the file system in C# to write unit tests? In my current case I have methods that check whether certain file exists and read the creation date. I may need more than that in future.

+1  A: 

I'm not sure how you would mock up the file system. What you could do is write a test fixture setup that creates a folder, etc. with the necessary structure for the tests. A teardown method would clean it up after the tests run.

Edited to add: In thinking about this a little more, I don't think you want to mock the file system to test this type of methods. If you mock the file system to return true if a certain file exists and use that in your test of a method that checks if that file exists, then you're not testing much of anything. Where mocking the file system would be useful is if you wanted to test a method that had a dependency on the file system but the file system activity was not integral to the method under test.

Jamie Ide
+2  A: 

You're probably going to have to build a contract to define what things you need from the file system and then write a wrapper around those functionalities. At that point you'd be able to mock or stub out the implementation.

Example:

interface IFileWrapper { bool Exists(String filePath); }

class FileWrapper: IFileWrapper
{
    bool Exists(String filePath) { return File.Exists(filePath); }        
}

class FileWrapperStub: IFileWrapper
{
    bool Exists(String filePath) 
    { return if (filePath == @"C:\myfilerocks.txt"); }
}
Joseph
+1  A: 

It would be difficult to mock the file system in a test since the .NET file APIs are not really based on interfaces or extensible classes that could be mocked.

However, if you have your own functional layer to access the file system, you could mock that in a unit test.

As an alternative to mocking, consider just creating the folders and files you need as part of your test setup, and deleting them in your teardown method.

LBushkin
+29  A: 

You could do it by creating an interface:

interface IFileSystem {
    bool FileExists(string fileName);
    DateTime GetCreationDate(string fileName);
}

and creating a 'real' implementation which uses System.IO.File.Exists() etc. You can then mock this interface using a mocking framework; I recommend Moq.

Edit: somebody's done this and kindly posted it online here.

I've used this approach to mock out DateTime.UtcNow in an IClock interface (really really useful for our testing to be able to control the flow of time!), and more traditionally, an ISqlDataAccess interface.

Another approach might be to use TypeMock, this allows you to intercept calls to classes and stub them out. This does however cost money, and would need to be installed on your whole team's PCs and your build server in order to run, also, it apparently won't work for the System.IO.File, as it can't stub mscorlib.

You could also just accept that certain methods are not unit testable and test them in a separate slow-running integration/system tests suite.

Matt Howells
In my opinion, creating an interface as Matt describes here is the way to go. I've even written a tool that generates such interfaces for you, which is useful when trying to mock static and/or sealed classes, or methods that are non-deterministic (i.e. clocks and random number generators). See http://jolt.codeplex.com for more information.
Steve Guidi
A: 

I would go with Jamie Ide's response. Don't try to mock out things that you didn't write. There will be all manner of dependancies you didn't know about - sealed classes, non virtual methods etc.

Another approach would be to wrap the appopiate methods with something that is mockable. e.g. create a class called FileWrapper that allows access to the File methods but is something you can mock out.

gbanfill
+1  A: 

To answer your specific question: No, there are no libraries that will allow you to mock file I/O calls (that I know of). This means that "properly" unit testing your types will require that you take this restriction into consideration when you define your types.

Quick side note about how I define a "proper" unit test. I believe that unit tests should confirm that you get the expected output (be that an exception, call on a method, etc) provided known inputs. This allows you to set up your unit test conditions as a set of inputs and/or input states. The best way I've found to do this is using interface-based services and dependency injection so that each responsibility external to a type is provided via an interface passed via a constructor or property.

So, with this in mind, back to your question. I've mocked file system calls by creating a IFileSystemService interface along with a FileSystemService implementation that is simply a facade over the mscorlib file system methods. My code then uses the IFileSystemService rather than the mscorlib types. This allows me to plug in my standard FileSystemService when the application is running or mock the IFileSystemService in my unit tests. The application code is same regardless of how it's run, but the underlying infrastructure allows that code to be easily tested.

I'll acknowledge that it's a pain to use the wrapper around the mscorlib file system objects but, in these specific scenarios, it's worth the extra work as the testing becomes so much easier and more reliable.

akmad
+6  A: 

I'd have added this as a comment, but I don't have the reputation :)

I'd absolutely agree to write your own interface and mock that.

The biggest advantage is that you can define your own interface and the expected behavior of it, and test against that. For the file existing case, you can say "this should take a string as a path, return a bool, and never throw." That's a reasonable definition of an API, and you can be relatively confident of being able to write code to do exactly that.

The problem with "mocking" an existing interface that you don't own is that you end up testing not the actual behavior of the object, but whether or not your mock behavior matches the real behavior of the system or not - that may not be what you want to test. Testing if your usage of another API is correct is probably better done in an integration style test, using the actual dependency.

kyoryu
A: 

We currently use a proprietary data engine and its API is not exposed as interfaces so we can hardly unit test our data access code. Then I went with Matt and Joseph's approach too.

Tiendq
A: 

Creating an interface and mocking it for testing is the cleanest way to go. However, as an alternative yo could take a look at the Microsoft Moles framework.

Konamiman
A: 

I've come across the following solutions to this:

  • Write Integration tests, not unit tests. For this to work you need a simple way of creating a folder where you can dump stuff without worrying about other tests interfering. I have a simple TestFolder class which can create a unique per test method folder to use.
  • Write a mockable System.IO.File. That is create a IFile.cs. I find using this often ends up with tests that simply prove you can write mocking statements, but do use it when the IO usage is small.
  • Examine you layer of abstraction, and extract the file IO from the class. The create a interface for this. The remainder use integration tests (but this will be very small). This differs from above in that instead of doing file.Read you write the intent, say ioThingie.loadSettings()
  • System.IO.Abstractions. I've not used this yet, but it is the one I'm most excited about playing with.

I end up using all the methods above, depending on what I'm writing. But most of the time I end up thinking abstraction is wrong when I write unit tests that hit the IO.

mlk