SuperAPI AI Directory

dotnet-testing-filesystem-testing-abstractions

Testing & quality

View repository

Updated 10-15 23:45

About this skill

File System Testing: Simulating File Operations Using System.IO.Abstractions

Core Principles

1. The Fundamental Problem of File System Dependencies

Code that traditionally directly uses System.IO static classes is difficult to test, for reasons including:

  • Speed Issues: Actual disk IO is 10-100 times slower than memory operations
  • Environment Dependency: Test results are affected by file system state, permissions, and paths
  • Side Effects: Tests leave traces on disk, affecting other tests
  • Concurrency Issues: Multiple tests operating on the same file simultaneously create race conditions
  • Difficulty Simulating Errors: Difficult to simulate exceptions such as insufficient permissions or insufficient disk space

2. System.IO.Abstractions Solution

A package that wraps System.IO static classes into interfaces, supporting dependency injection and test doubles.

Required NuGet Packages:

<!-- 正式環境 -->
<PackageReference Include="System.IO.Abstractions" Version="22.1.0" />

<!-- 測試專案 -->
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="22.1.0" />

3. Refactoring Steps

Step One: Change code that directly uses static classes to depend on IFileSystem

// ❌ 重構前(不可測試)
public class ConfigService
{
    public string LoadConfig(string path) => File.ReadAllText(path);
}

// ✅ 重構後(可測試)
public class ConfigService
{
    private readonly IFileSystem _fileSystem;
    public ConfigService(IFileSystem fileSystem) => _fileSystem = fileSystem;
    public string LoadConfig(string path) => _fileSystem.File.ReadAllText(path);
}

Step Two: Register the real implementation in the DI container

services.AddSingleton<IFileSystem, FileSystem>();

Step Three: Use MockFileSystem in tests

var mockFs = new MockFileSystem(new Dictionary<string, MockFileData>
{
    ["config.json"] = new MockFileData("{ \"key\": \"value\" }")
});
var service = new ConfigService(mockFs);

MockFileSystem Testing Patterns

Covers four core testing patterns: default file state setup, verifying write results, directory operation testing, and using NSubstitute to simulate IO exceptions (UnauthorizedAccessException, etc.). Also includes advanced techniques: stream operation testing, file information query testing, and backup file testing.

For complete MockFileSystem testing patterns and advanced techniques, refer to references/mockfilesystem-patterns.md

Best Practices

Should Do

  1. Use Path.Combine to handle paths — _fileSystem.Path.Combine("configs", "app.json")
  2. Defensively check file existence — check before reading _fileSystem.File.Exists()
  3. Automatically create necessary directories — ensure the directory exists before writing
  4. Properly handle various IO exceptions — UnauthorizedAccessException、IOException、DirectoryNotFoundException
  5. Use an independent MockFileSystem for each test — ensure test isolation

Should Avoid

  1. Hardcoding path separators — use Path.Combine instead of \\ or /
  2. Using the real file system in unit tests — use MockFileSystem
  3. Ignoring exception handling — do not assume files definitely exist

Performance Considerations

  • MockFileSystem Speed: 10-100 times faster than real file operations
  • Memory Usage: Only create files necessary for the test, avoid simulating extremely large files

Practical Integration Examples

Please refer to templates/ for complete implementations under the directory:

  • configmanager-service.cs - Configuration file management service (load/save/backup)
  • filemanager-service.cs - File management service (copy/directory operations/error handling)

Output Format

  • Generate a service class that uses the IFileSystem interface
  • Generate a test class that uses MockFileSystem
  • Include test examples for file reading and writing, directory operations, and path handling
  • Provide .csproj package references (System.IO.Abstractions, System.IO.Abstractions.TestingHelpers)

Reference Resources

Original Article

The content of this skill is distilled from the "Old-School Software Engineer's Testing Practice - 30-Day Challenge" article series:

Official Documentation

Related Skills

  • nsubstitute-mocking - Test Doubles and Mocking
  • unit-test-fundamentals - Unit Testing Fundamentals