Testably.Abstractions
Testably.Abstractions is a feature-complete testing helper for the IFileSystem abstractions of the System.IO namespace, plus matching abstractions for time and randomness.
Inject. Mock. Test.
Depend on IFileSystem, ITimeSystem and IRandomSystem in production. Swap in the in-memory mocks for tests — deterministic, cross-platform, no temp folders or Thread.Sleep.
- File system
- Time system
- Random system
ReportService.cs
public class ReportService(IFileSystem fileSystem)
{
public void Save(string content)
{
fileSystem.Directory.CreateDirectory("reports");
fileSystem.File.WriteAllText("reports/latest.xml", content);
}
}
ReportServiceTests.cs
[Fact]
public async Task Save_WritesReportToReportsFolder()
{
var fileSystem = new MockFileSystem();
var sut = new ReportService(fileSystem);
sut.Save("<report />");
await Expect.That(fileSystem.File.ReadAllText("reports/latest.xml"))
.IsEqualTo("<report />");
}
CacheEntry.cs
public class CacheEntry(ITimeSystem timeSystem, TimeSpan ttl)
{
private readonly DateTime _expiresAt = timeSystem.DateTime.UtcNow + ttl;
public bool IsExpired => timeSystem.DateTime.UtcNow >= _expiresAt;
}
CacheEntryTests.cs
[Fact]
public async Task IsExpired_ReturnsTrue_AfterTtlPasses()
{
MockTimeSystem timeSystem = new(new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc));
var entry = new CacheEntry(timeSystem, TimeSpan.FromMinutes(5));
await timeSystem.Task.Delay(TimeSpan.FromMinutes(6));
await Expect.That(entry.IsExpired).IsTrue();
}
CorrelationIdProvider.cs
public class CorrelationIdProvider(IRandomSystem randomSystem)
{
public string Next() => randomSystem.Guid.NewGuid().ToString();
}
CorrelationIdProviderTests.cs
[Fact]
public async Task Next_ReturnsConfiguredGuid_ForDeterministicTests()
{
MockRandomSystem randomSystem = new(RandomProvider.Generate(
guidGenerator: () => Guid.Parse("11111111-1111-1111-1111-111111111111")));
var sut = new CorrelationIdProvider(randomSystem);
await Expect.That(sut.Next())
.IsEqualTo("11111111-1111-1111-1111-111111111111");
}
Why another file system mock?
Testably.Abstractions shares the IFileSystem interface with TestableIO.System.IO.Abstractions - your production code does not change when you switch testing libraries. What you get on top:
- Advanced testing scenarios:
FileSystemWatcher,SafeFileHandle, multiple drives with size limits. - Cross-platform simulation: run a Linux file system on Windows (and vice versa) to exercise platform-specific behaviour from a single CI job.
- A second abstraction layer for time and randomness.
See Migration from TestableIO if you are already using TestableIO.
Where to go next
- Getting Started — install the packages and wire them up.
- File system, Time system, Random system — explore each abstraction.
- Companion libraries — ZIP and ACL helpers.