C# 如何使用System.IO.Abstractions中的FileSystemWatcher监视模拟文件系统?
我正在尝试创建一个类来监视Linux上USB设备的到达和删除。在Linux上,USB设备表示为C# 如何使用System.IO.Abstractions中的FileSystemWatcher监视模拟文件系统?,c#,filesystems,filesystemwatcher,C#,Filesystems,Filesystemwatcher,我正在尝试创建一个类来监视Linux上USB设备的到达和删除。在Linux上,USB设备表示为/dev/bus/USB下的设备文件,这些文件是为响应这些事件而创建/删除的 跟踪这些事件的最佳方法似乎是使用FileSystemWatcher。为了使类可测试,我在构建过程中使用并向类注入IFileSystem的实例。我想要的是创建一个行为类似于文件系统观察者的东西,但是监视对注入的IFileSystem的更改,而不是直接监视真正的文件系统 查看System.IO.Abstractions中的File
/dev/bus/USB
下的设备文件,这些文件是为响应这些事件而创建/删除的
跟踪这些事件的最佳方法似乎是使用FileSystemWatcher
。为了使类可测试,我在构建过程中使用并向类注入IFileSystem
的实例。我想要的是创建一个行为类似于文件系统观察者的东西,但是监视对注入的IFileSystem
的更改,而不是直接监视真正的文件系统
查看System.IO.Abstractions
中的FileSystemWatcherBase
和filesystemwatcherrapper
,我不知道该怎么做。目前我有这个(我知道这是错误的):
公共DevMonitor(
[NotNull]IFileSystem文件系统,
[NotNull]IDeviceFileParser设备文件解析器,
[NotNull]ILogger记录器,
[NotNull]字符串devDirectoryPath=DefaultDevDirectoryPath)
{
Raise.ArgumentNullException.ifisnall(记录器,名称(记录器));
Raise.ArgumentNullException.ifisnall(devDirectoryPath,name of(devDirectoryPath));
_fileSystem=fileSystem??抛出新的ArgumentNullException(文件系统名称));
_deviceFileParser=deviceFileParser??抛出新的ArgumentNullException(nameof(deviceFileParser));
_logger=logger.ForContext();
_watcher=newfilesystemwatcherrapper(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();
}
/// <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();
}
在我的单元测试类中,我将其实现为MockWatchableFileSystem
,它将MockFileSystem
和Mock
公开为属性,我可以使用这些属性在测试中安排和断言:
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;
}
在测试期间,客户机将获得一个IWatchableFileSystem
,它包装MockFileSystem
,并返回FileSystemWatcherBase
的模拟实例。在生产过程中,它会得到一个IWatchableFileSystem
,它包装文件系统
,并生成FileSystemWatcher的唯一实例
我能问一下否决票是为了什么吗?我认为这是不可能的。FileSystemWatcher类根本不可扩展(甚至没有任何有用的虚拟方法)。相反,将FileSystemWatcher抽象到某个接口后面,该接口创建了etc事件,并在单元测试中手动触发这些事件。因此,在将目录添加到您的IFileSystem
之后,您可以自己触发相应的事件。这是一种方法,但我希望我不必求助于此。我不希望他们直接扩展FileSystemWatcher
,但可能会有类似工厂IFileSystem=>IFileSystemWatcher
的东西,该工厂检查提供的IFileSystem
是真实的还是模拟的。如果为真,则返回标准FileSystemWatcher
的包装。如果是mock,则返回一个自定义类,该类监视对mock文件系统的更改。我想您必须自己实现它,或者解决github的问题,并希望作者能够实现它。已经有一个关于实现mock FileSystemWatcher的问题:,已经有一年了,所以我不希望很快有结果。啊,干杯。那太糟糕了。
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;
}
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;
}