File system
IFileSystem abstracts away every I/O type from System.IO so you can inject and replace it. The interface is API-compatible with TestableIO.System.IO.Abstractions: production code written against one library works with the other.
How the BCL maps onto the interface
Static / new in System.IO | IFileSystem member |
|---|---|
File.ReadAllText("catalog.json") | fileSystem.File.ReadAllText("catalog.json") |
Directory.CreateDirectory("vault") | fileSystem.Directory.CreateDirectory("vault") |
Path.Combine("vault", "red-square.png") | fileSystem.Path.Combine("vault", "red-square.png") |
new FileInfo("catalog.json") | fileSystem.FileInfo.New("catalog.json") |
new DirectoryInfo("vault") | fileSystem.DirectoryInfo.New("vault") |
new FileStream(...) | fileSystem.FileStream.New(...) |
new FileSystemWatcher(...) | fileSystem.FileSystemWatcher.New(...) |
DriveInfo.GetDrives() | fileSystem.DriveInfo.GetDrives() |
FileVersionInfo.GetVersionInfo(...) | fileSystem.FileVersionInfo.GetVersionInfo(...) |
Static methods stay static on the sub-properties; constructors become factory methods (New). Everything else mirrors the framework one-to-one.
Implementations
| Type | Package | Use it for |
|---|---|---|
RealFileSystem | Testably.Abstractions | Production |
MockFileSystem | Testably.Abstractions.Testing | Unit tests |
MockFileSystem is the in-memory implementation of IFileSystem shipped in Testably.Abstractions.Testing. It implements every member of IFileSystem and is exercised by the same test suite as RealFileSystem: if a test passes against the real file system, it passes against the mock, and vice versa.
IFileSystem fileSystem = new MockFileSystem();
fileSystem.File.WriteAllText("red-square.txt", "Oil on canvas");
string content = fileSystem.File.ReadAllText("red-square.txt"); // "Oil on canvas"
Configuring the mock
MockFileSystem accepts an options builder (MockFileSystemOptions):
MockFileSystem fileSystem = new(o => o
.UseCurrentDirectory("/gallery") // sets CurrentDirectory to "/gallery"
.UseTimeSystem(timeSystem) // share an existing MockTimeSystem
.UseRandomProvider(randomProvider) // share an existing IRandomProvider
.SimulatingOperatingSystem(SimulationMode.Linux)); // simulate Linux semantics
UseCurrentDirectory() (no argument) seeds the mock with the host's actual working directory, useful when test code uses relative paths and you want them to resolve against the same place the real system would.
The mock also exposes MockFileSystem.TimeSystem and MockFileSystem.RandomSystem if you didn't wire them in yourself. Use them to assert against the same instances the file system is using internally.
In this section
Initialization
Seed a MockFileSystem declaratively, fluently, from a real directory or from embedded resources.
Simulating other operating systems
Run the MockFileSystem with Linux, macOS or Windows semantics, independent of the host.
Drives
Add drives with size limits, UNC shares and removable drives to the MockFileSystem.
FileSystemWatcher
Use the mocked FileSystemWatcher, which raises the same OS-specific events as the real one.
Intercept & notify
Abort file system operations before they complete, or wait for them after they completed.
Statistics
Assert which file system methods and properties the code under test used.
Access denial (ACL)
Deny access to selected paths in the MockFileSystem to test how code handles missing Windows permissions.
Unix file mode
Simulate POSIX users, groups and permissions in the MockFileSystem.
SafeFileHandle
Use SafeFileHandle overloads against the MockFileSystem, including handles that come from outside the mock.
RandomAccess
Read and write files at explicit offsets through a SafeFileHandle, on the real and the mocked file system.
FileVersionInfo
Return deterministic FileVersionInfo values for files in the MockFileSystem.
Extensibility
Attach custom metadata to entries of the MockFileSystem when writing strategies or extension methods.