如何使用 System.IO.Abstractions 中的 FileSystemWatcher 来监视模拟文件系统?
How can I use FileSystemWatcher from System.IO.Abstractions to monitor a mock filesystem?
我正在尝试创建一个 class 来监控 USB 设备在 Linux 上的到达和移除。在 Linux 上,USB 设备表示为 /dev/bus/usb
下的设备文件,这些文件是 created/deleted 以响应这些事件。
似乎跟踪这些事件的最佳方式是使用 FileSystemWatcher
。为了使 class 可测试,我使用 System.IO.Abstractions
并在构造期间将 IFileSystem
的实例注入 class。我想要的是创建一些行为类似于 FileSystemWatcher
的东西,但监视对注入的 IFileSystem
的更改,而不是直接监视真正的文件系统。
查看 System.IO.Abstractions
中的 FileSystemWatcherBase
和 FileSystemWatcherWrapper
,我不确定该怎么做。目前我有这个(我知道这是错误的):
public DevMonitor(
[NotNull] IFileSystem fileSystem,
[NotNull] IDeviceFileParser deviceFileParser,
[NotNull] ILogger logger,
[NotNull] string devDirectoryPath = DefaultDevDirectoryPath)
{
Raise.ArgumentNullException.IfIsNull(logger, nameof(logger));
Raise.ArgumentNullException.IfIsNull(devDirectoryPath, nameof(devDirectoryPath));
_fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
_deviceFileParser = deviceFileParser ?? throw new ArgumentNullException(nameof(deviceFileParser));
_logger = logger.ForContext<DevMonitor>();
_watcher = new FileSystemWatcherWrapper(devDirectoryPath);
}
鉴于 System.IO.Abstractions
似乎还不支持这一点,我选择了这个:
我定义了一个扩展 IFileSystem
:
的 IWatchableFileSystem
接口
/// <summary>
/// Represents a(n) <see cref="IFileSystem" /> that can be watched for changes.
/// </summary>
public interface IWatchableFileSystem : IFileSystem
{
/// <summary>
/// Creates a <c>FileSystemWatcher</c> that can be used to monitor changes to this file system.
/// </summary>
/// <returns>A <c>FileSystemWatcher</c>.</returns>
FileSystemWatcherBase CreateWatcher();
}
出于生产目的,我将其实现为 WatchableFileSystem
:
/// <inheritdoc />
public sealed class WatchableFileSystem : IWatchableFileSystem
{
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="WatchableFileSystem" /> class.
/// </summary>
public WatchableFileSystem() => _fileSystem = new FileSystem();
/// <inheritdoc />
public DirectoryBase Directory => _fileSystem.Directory;
/// <inheritdoc />
public IDirectoryInfoFactory DirectoryInfo => _fileSystem.DirectoryInfo;
/// <inheritdoc />
public IDriveInfoFactory DriveInfo => _fileSystem.DriveInfo;
/// <inheritdoc />
public FileBase File => _fileSystem.File;
/// <inheritdoc />
public IFileInfoFactory FileInfo => _fileSystem.FileInfo;
/// <inheritdoc />
public PathBase Path => _fileSystem.Path;
/// <inheritdoc />
public FileSystemWatcherBase CreateWatcher() => new FileSystemWatcher();
}
在我的单元测试 class 中,我将其实现为 MockWatchableFileSystem
,它将 MockFileSystem
和 Mock<FileSystemWatcherBase>
公开为我可以在测试中用于安排和断言的属性:
private class MockWatchableFileSystem : IWatchableFileSystem
{
/// <inheritdoc />
public MockWatchableFileSystem()
{
Watcher = new Mock<FileSystemWatcherBase>();
AsMock = new MockFileSystem();
AsMock.AddDirectory("/dev/bus/usb");
Watcher.SetupAllProperties();
}
public MockFileSystem AsMock { get; }
/// <inheritdoc />
public DirectoryBase Directory => AsMock.Directory;
/// <inheritdoc />
public IDirectoryInfoFactory DirectoryInfo => AsMock.DirectoryInfo;
/// <inheritdoc />
public IDriveInfoFactory DriveInfo => AsMock.DriveInfo;
/// <inheritdoc />
public FileBase File => AsMock.File;
/// <inheritdoc />
public IFileInfoFactory FileInfo => AsMock.FileInfo;
/// <inheritdoc />
public PathBase Path => AsMock.Path;
public Mock<FileSystemWatcherBase> Watcher { get; }
/// <inheritdoc />
public FileSystemWatcherBase CreateWatcher() => Watcher.Object;
}
最后,在我的客户端中 class 我可以这样做:
public DevMonitor(
[NotNull] IWatchableFileSystem fileSystem,
[NotNull] IDeviceFileParser deviceFileParser,
[NotNull] ILogger logger,
[NotNull] string devDirectoryPath = DefaultDevDirectoryPath)
{
// ...
_watcher = fileSystem.CreateWatcher();
_watcher.IncludeSubdirectories = true;
_watcher.EnableRaisingEvents = true;
_watcher.Path = devDirectoryPath;
}
在测试期间,客户端得到一个 IWatchableFileSystem
包装 MockFileSystem
和 returns 一个 FileSystemWatcherBase
的模拟实例。在生产过程中,它得到一个 IWatchableFileSystem
包装 FileSystem
并生成 FileSystemWatcher
.
的唯一实例
我正在尝试创建一个 class 来监控 USB 设备在 Linux 上的到达和移除。在 Linux 上,USB 设备表示为 /dev/bus/usb
下的设备文件,这些文件是 created/deleted 以响应这些事件。
似乎跟踪这些事件的最佳方式是使用 FileSystemWatcher
。为了使 class 可测试,我使用 System.IO.Abstractions
并在构造期间将 IFileSystem
的实例注入 class。我想要的是创建一些行为类似于 FileSystemWatcher
的东西,但监视对注入的 IFileSystem
的更改,而不是直接监视真正的文件系统。
查看 System.IO.Abstractions
中的 FileSystemWatcherBase
和 FileSystemWatcherWrapper
,我不确定该怎么做。目前我有这个(我知道这是错误的):
public DevMonitor(
[NotNull] IFileSystem fileSystem,
[NotNull] IDeviceFileParser deviceFileParser,
[NotNull] ILogger logger,
[NotNull] string devDirectoryPath = DefaultDevDirectoryPath)
{
Raise.ArgumentNullException.IfIsNull(logger, nameof(logger));
Raise.ArgumentNullException.IfIsNull(devDirectoryPath, nameof(devDirectoryPath));
_fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
_deviceFileParser = deviceFileParser ?? throw new ArgumentNullException(nameof(deviceFileParser));
_logger = logger.ForContext<DevMonitor>();
_watcher = new FileSystemWatcherWrapper(devDirectoryPath);
}
鉴于 System.IO.Abstractions
似乎还不支持这一点,我选择了这个:
我定义了一个扩展 IFileSystem
:
IWatchableFileSystem
接口
/// <summary>
/// Represents a(n) <see cref="IFileSystem" /> that can be watched for changes.
/// </summary>
public interface IWatchableFileSystem : IFileSystem
{
/// <summary>
/// Creates a <c>FileSystemWatcher</c> that can be used to monitor changes to this file system.
/// </summary>
/// <returns>A <c>FileSystemWatcher</c>.</returns>
FileSystemWatcherBase CreateWatcher();
}
出于生产目的,我将其实现为 WatchableFileSystem
:
/// <inheritdoc />
public sealed class WatchableFileSystem : IWatchableFileSystem
{
private readonly IFileSystem _fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="WatchableFileSystem" /> class.
/// </summary>
public WatchableFileSystem() => _fileSystem = new FileSystem();
/// <inheritdoc />
public DirectoryBase Directory => _fileSystem.Directory;
/// <inheritdoc />
public IDirectoryInfoFactory DirectoryInfo => _fileSystem.DirectoryInfo;
/// <inheritdoc />
public IDriveInfoFactory DriveInfo => _fileSystem.DriveInfo;
/// <inheritdoc />
public FileBase File => _fileSystem.File;
/// <inheritdoc />
public IFileInfoFactory FileInfo => _fileSystem.FileInfo;
/// <inheritdoc />
public PathBase Path => _fileSystem.Path;
/// <inheritdoc />
public FileSystemWatcherBase CreateWatcher() => new FileSystemWatcher();
}
在我的单元测试 class 中,我将其实现为 MockWatchableFileSystem
,它将 MockFileSystem
和 Mock<FileSystemWatcherBase>
公开为我可以在测试中用于安排和断言的属性:
private class MockWatchableFileSystem : IWatchableFileSystem
{
/// <inheritdoc />
public MockWatchableFileSystem()
{
Watcher = new Mock<FileSystemWatcherBase>();
AsMock = new MockFileSystem();
AsMock.AddDirectory("/dev/bus/usb");
Watcher.SetupAllProperties();
}
public MockFileSystem AsMock { get; }
/// <inheritdoc />
public DirectoryBase Directory => AsMock.Directory;
/// <inheritdoc />
public IDirectoryInfoFactory DirectoryInfo => AsMock.DirectoryInfo;
/// <inheritdoc />
public IDriveInfoFactory DriveInfo => AsMock.DriveInfo;
/// <inheritdoc />
public FileBase File => AsMock.File;
/// <inheritdoc />
public IFileInfoFactory FileInfo => AsMock.FileInfo;
/// <inheritdoc />
public PathBase Path => AsMock.Path;
public Mock<FileSystemWatcherBase> Watcher { get; }
/// <inheritdoc />
public FileSystemWatcherBase CreateWatcher() => Watcher.Object;
}
最后,在我的客户端中 class 我可以这样做:
public DevMonitor(
[NotNull] IWatchableFileSystem fileSystem,
[NotNull] IDeviceFileParser deviceFileParser,
[NotNull] ILogger logger,
[NotNull] string devDirectoryPath = DefaultDevDirectoryPath)
{
// ...
_watcher = fileSystem.CreateWatcher();
_watcher.IncludeSubdirectories = true;
_watcher.EnableRaisingEvents = true;
_watcher.Path = devDirectoryPath;
}
在测试期间,客户端得到一个 IWatchableFileSystem
包装 MockFileSystem
和 returns 一个 FileSystemWatcherBase
的模拟实例。在生产过程中,它得到一个 IWatchableFileSystem
包装 FileSystem
并生成 FileSystemWatcher
.