Fork me on GitHub

IO Access

Motivation

The .Net framework doesn't provide a convenient way to intercept or test calls to the file system.

The Access namespace of Appccelerate provides an abstraction over the .Net file system classes that allow both extensibility and testability.

Sample

Instead of using the .net framework classes directly like File.WriteAllText, use an IAccessFactory to create a File. And then write the file.

The File class and all other abstraction classes provide exactly the same methods as the original ones from the .Net framework.

Testability

Using the indirection via the access factory allows you to test this code without really writing to the file system.

Faking IFile, IDirectory etc.

One way to test code interacting with the file system is to fake the classes that make calls to the file system:

This unit test is written using xUnit (test framework) and FakeItEasy (fake/mock library).

The test checks whether the file was written to the expected path and with the expected content by verifying that the corresponding call on the IFile was made.

Faking is best suited for unit tests for classes with little interaction or lot of special cases like access violations and so on.

In-memory File System

Another way to test code interacting with the file system is to use the in-memory file system:

This test checks whether a file was written, by inspecting the in-memory file system.

The in-memory file system is best suited in tests that have a lot of interaction with the file system. For example in acceptance tests. Using the in-memory file system leads to simpler to understand tests that setting up all the fake calls as seen above. Testing special cases however is tricky.

Current Limitations

The in-memory file system is only partly implemented at the moment (there are really a lot of methods to interact with the file system!). More will be added in the future. Or just contribute what you need ;-)

You cannot use the in-memory file system together with extensions. This is something we are working on.

Extensibility

The access factory allows to register extensions.

For every call to the file system (e.g. File.ReadAllBytes), all registered file extensions get a call to

with <MethodName> being the name of the method that is/was called.

The Begin<MethodName> methods have the same arguments as the method being called.

The End<MethodName> methods have no arguments for void methods and the result of the called method otherwise.

The Fail<MethodName> methods have the thrown exception as the argument. (we are currently working on adding the original arguments)

Example

This example shows how to add an extension that logs File.WriteAllText calls.
Add the extension:


accessFactory.RegisterFileExtensionsProvider(() => new[] { new LogFileExtension() });

Write the extension:

There exist base classes for all extension types so that you only have to implement the methods you are interested in.

There are the following types of extensions:

Note: If you want to intercept all calls to the file system, you can either implement an extension per extension type and implement all methods of these, or use a code weaver (PostSharp, Fody) to create this code.

Road Map

What we intend to add to the IO Access namespace in the future.