Initialization
You can seed a MockFileSystem declaratively (with descriptions), fluently (with a builder), or by copying data in from outside the test.
The first two snippets create:
- a directory
foo/containing a sub-directorybar/and an empty filebar.txt - a file
foo.txtwith content"some file content"
Declarative
var fileSystem = new MockFileSystem();
fileSystem.Initialize().With(
new DirectoryDescription("foo",
new DirectoryDescription("bar"),
new FileDescription("bar.txt")),
new FileDescription("foo.txt", "some file content"));
Fluent
var fileSystem = new MockFileSystem();
fileSystem.Initialize()
.WithSubdirectory("foo").Initialized(d => d
.WithSubdirectory("bar")
.WithFile("bar.txt"))
.WithFile("foo.txt").Which(f => f.HasStringContent("some file content"));
Use HasStringContent(string) or HasBytesContent(byte[]) on the file manipulator to set content.
Initializing inside a specific directory
fileSystem.InitializeIn("current-directory")
.WithASubdirectory()
.WithSubdirectory("foo").Initialized(s => s
.WithAFile())
.WithFile("bar.txt");
This sets current-directory as the working directory and seeds it with:
- a randomly named sub-directory
- a
foo/sub-directory containing one randomly named file - a
bar.txtfile
WithASubdirectory() / WithAFile() use generated names when you don't care about the exact value - useful for tests that operate over whatever they find. WithAFile(string extension) lets you constrain the random name to a specific extension.
InitializeIn(absolutePath) automatically registers the corresponding drive on Windows when the path is rooted.
Bulk subdirectories
fileSystem.Initialize()
.WithSubdirectories("a/b/c", "x/y", "logs");
Creates each path (and any missing parents) in one call.
Accessing what was created
Initialize() returns an IFileSystemInitializer<TFileSystem> exposing:
BaseDirectory- theIDirectoryInfoof the seed rootFileSystem- the underlying file systemthis[int index]- the created entries in the order they were added
var init = fileSystem.Initialize()
.WithFile("foo.txt")
.WithSubdirectory("bar");
var foo = (IFileInfo)init[0];
var bar = (IDirectoryInfo)init[1];
Seeding from a real directory
fileSystem.InitializeFromRealDirectory("test-data");
// or copy the source directory into a different target on the mock:
fileSystem.InitializeFromRealDirectory(@"C:\fixtures\sample-project", "project");
Recursively copies every file and sub-directory from the real path into the mock, preserving creation/last-write/last-access time and attributes. With large fixtures this can be slow - prefer it for small, hand-curated test data.
Seeding from embedded resources
fileSystem.InitializeEmbeddedResourcesFromAssembly(
directoryPath: "fixtures",
assembly: typeof(MyTests).Assembly,
relativePath: "TestData",
searchPattern: "*.json",
searchOption: SearchOption.AllDirectories);
Materializes embedded resources as files inside the mock. Resource names are split on the last . to recover an extension (e.g. MyTests.TestData.users.json becomes fixtures/users.json). relativePath filters which resources are included; searchPattern and searchOption work like Directory.EnumerateFiles.
Skipping the implicit temp directory
By default, Initialize() and InitializeIn() also materialize the system temp directory inside the mock, so code that calls Path.GetTempPath() finds something there. Pass an options callback to opt out:
fileSystem.Initialize(o => o.InitializeTempDirectory = false);
Errors during initialization
The fluent builders throw TestingException (in Testably.Abstractions.Testing.Initializer) when used incorrectly - for example calling WithFile("foo") twice in the same parent scope. Catch this type if you need to surface a friendly assertion in a custom helper.
Real file system: temporary directory with auto-cleanup
For integration tests that hit the real disk, SetCurrentDirectoryToEmptyTemporaryDirectory creates a fresh temp directory, switches Directory.GetCurrentDirectory() to it, and force-deletes everything when the returned IDirectoryCleaner is disposed:
IFileSystem fileSystem = new RealFileSystem();
using IDirectoryCleaner cleaner =
fileSystem.SetCurrentDirectoryToEmptyTemporaryDirectory(prefix: "MyTests-");
// fileSystem.Directory.GetCurrentDirectory() is now an empty temp directory
// On dispose: the directory is force-deleted (read-only flag and all)
The prefix parameter makes leftovers easier to spot in %TEMP% if cleanup ever fails. The optional logger parameter receives diagnostic messages (e.g. retry attempts when antivirus holds a file open).