How do you mock out the file system in C# for unit testing?
Edit: Install the NuGet package System.IO.Abstractions
.
This package did not exist when this answer was originally accepted. The original answer is provided for historical context below:
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.
This imaginary library exists now, there is a NuGet package for System.IO.Abstractions, which abstracts away the System.IO namespace.
There is also a set of test helpers, System.IO.Abstractions.TestingHelpers which - at the time of writing - is only partially implemented, but is a very good starting point.
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 (filePath == @"C:\myfilerocks.txt"); }
}