You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确Mock IFileSystem与IFileSystemWatcher?文件删除时OnChanged未触发

解决Mock环境下FileSystemWatcher事件不触发的问题

问题根源分析

  • 错误Mock了TestFileWatcher本身:要测试的是这个类的真实逻辑,不该Mock它,Mock对象应该是它的依赖组件。
  • MockFileSystem默认的FileSystemWatcherFactory无自动事件触发逻辑:模拟文件系统的操作(比如删除)不会主动通知Watcher,需要手动触发事件。
  • OnChanged方法依赖真实文件系统:直接实例化FileInfo会绕过注入的IFileSystem,在Mock环境中引发不一致问题。

修复步骤

1. 修正TestFileWatcher的文件系统依赖逻辑

把OnChanged里的真实FileInfo替换为IFileSystem提供的实例,保持依赖注入一致性:

private void OnChanged(object source, FileSystemEventArgs e)
{
    // 使用注入的IFileSystem获取FileInfo,避免直接访问真实文件系统
    var fi = _fileSystem.FileInfo.FromFileName(e.FullPath);
    fi.Refresh();
    isDeleted = true;
}

2. 调整测试代码:移除TestFileWatcher的Mock,手动触发事件

直接实例化TestFileWatcher,手动模拟FileSystemWatcher的事件触发:

[Fact]
public void Mock_TestFileWatcher()
{
    var mockFileSystem = new MockFileSystem();
    mockFileSystem.AddFile("deleteFile", new MockFileData(""));

    // 直接实例化要测试的TestFileWatcher
    var testWatcher = new TestFileWatcher(mockFileSystem);

    // 获取TestFileWatcher使用的FileSystemWatcher实例(或模拟对应实例)
    var watcher = mockFileSystem.FileSystemWatcher.CreateNew();
    watcher.Path = mockFileSystem.Path.GetDirectoryName("deleteFile");
    watcher.Filter = mockFileSystem.Path.GetFileName("deleteFile");

    // 手动触发Deleted事件,模拟文件被删除的场景
    watcher.Deleted?.Invoke(null, new FileSystemEventArgs(
        WatcherChangeTypes.Deleted,
        mockFileSystem.Path.GetDirectoryName("deleteFile"),
        mockFileSystem.Path.GetFileName("deleteFile")
    ));

    Assert.True(testWatcher.isDeleted);
}

3. 更灵活的方案:用Moq精准Mock IFileSystemWatcher

通过Moq直接MockIFileSystemWatcher,并注入到TestFileWatcher中,完全控制事件触发:

[Fact]
public void Mock_TestFileWatcher_WithMoq()
{
    // Mock IFileSystemWatcher
    var mockWatcher = new Mock<IFileSystemWatcher>();
    // Mock IFileSystem,指定FileSystemWatcher的返回值
    var mockFileSystem = new Mock<IFileSystem>();
    mockFileSystem.Setup(fs => fs.FileSystemWatcher.CreateNew()).Returns(mockWatcher.Object);
    mockFileSystem.Setup(fs => fs.Path.GetDirectoryName("deleteFile")).Returns("");
    mockFileSystem.Setup(fs => fs.Path.GetFileName("deleteFile")).Returns("deleteFile");

    // 实例化TestFileWatcher
    var testWatcher = new TestFileWatcher(mockFileSystem.Object);

    // 手动触发Deleted事件
    mockWatcher.Raise(w => w.Deleted += null, 
        new FileSystemEventArgs(WatcherChangeTypes.Deleted, "", "deleteFile"));

    Assert.True(testWatcher.isDeleted);
}

关键注意事项

  • 不要Mock待测试的类:测试的核心是验证TestFileWatcher的真实逻辑,Mock的应该是它的依赖(如IFileSystem、IFileSystemWatcher)。
  • MockFileSystem的Watcher不会自动触发事件:模拟环境没有真实文件系统的事件通知机制,必须手动触发事件来模拟业务场景。
  • 所有文件操作通过注入的IFileSystem完成:避免直接使用System.IO下的类,确保测试完全在模拟环境中运行。

内容的提问来源于stack exchange,提问作者user2384330

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 18:30:17