单元测试FileSystemWatcher:如何以编程方式触发已更改的事件?

时间:2015-10-21 08:33:01

标签: c# .net unit-testing filesystemwatcher

我有一个FileSystemWatcher正在查看目录以进行更改,当其中包含新的XML文件时,它会解析该文件并对其执行某些操作。

我的项目中有一些示例XML文件,我用于我编写的解析器的单元测试目的。

我正在寻找一种方法来使用示例XML文件来测试FileSystemWatcher

是否可以以编程方式创建事件(以某种方式涉及XML文件)以触发FSW.Changed事件?

3 个答案:

答案 0 :(得分:10)

我认为你在这里采取了错误的做法。

你不应该试着直接对FileSystemWatcher类进行单元测试(你不能 - 你无法控制它!)。相反,您可以尝试以下方法:

1)为FileSystemWatcher类编写一个包装类,将其功能委托给FileSystemWatcher的实例。以下是一个方法和一个事件的示例,根据需要添加更多成员:

public class FileSystemWatcherWrapper
{
    private readonly FileSystemWatcher watcher;

    public event FileSystemEventHandler Changed;

    public FileSystemWatcherWrapper(FileSystemWatcher watcher)
    {
        this.watcher = watcher
        watcher.Changed += this.Changed;
    }

    public bool EnableRaisingEvents
    {
        get { return watcher.EnableRaisingEvents; }
        set { watcher.EnableRaisingEvents = value; }
    }
}

(注意如何将FileSystemWatcher的实例传递给类构造函数;您可以在构造包装器时动态创建新实例)

2)提取班级的接口:

public interface IFileSystemWatcherWrapper
{
    event FileSystemEventHandler Changed;
    bool EnableRaisingEvents { get; set; }
}

//and therefore...

public class FileSystemWatcherWrapper : IFileSystemWatcherWrapper

3)让你的班级依赖于界面:

public class TheClassThatActsOnFilesystemChanges
{
    private readonly IFileSystemWatcherWrapper fileSystemWatcher;

    public TheClassThatActsOnFilesystemChanges(IFileSystemWatcherWrapper fileSystemWatcher)
    {
        this.fileSystemWatcher = fileSystemWatcher;

        fileSystemWatcher.Changed += (sender, args) =>
        {
            //Do something...
        };
    }
}

4)在应用程序初始化时,使用任何依赖注入引擎实例化你的类,或者只是做穷人的注入:

var theClass = new TheClassThatActsOnFilesystemChanges(
    new FileSystemWatcherWrapper(new FileSystemWatcher()));

5)现在继续编写TheClassThatActsOnFilesystemChanges的单元测试,创建一个IFileSystemWatcherWrapper模拟器,根据您的意愿触发事件!您可以使用任何模拟引擎,例如Moq

底线:

当你对一个你不能控制的类和/或不能进行有意义的单元测试的依赖时,用一个合适的接口写一个环绕它,并依赖于接口。你的包装器非常薄,如果你不能对它进行单元测试,它就不会真正受到伤害,而你的客户端类现在可以进行适当的单元测试。

答案 1 :(得分:1)

只需从FileSystemWatcher派生并向界面添加您需要的任何内容:

public interface IFileSystemWatcherWrapper : IDisposable
{        
    bool EnableRaisingEvents { get; set; }
    event FileSystemEventHandler Changed;
    //...
}

public class FileSystemWatcherWrapper : FileSystemWatcher, IFileSystemWatcherWrapper
{
    public FileSystemWatcherWrapper(string path, string filter)
        : base(path, filter)
    {
    }
}

答案 2 :(得分:0)

由于FileSystemWatcher不是密封的类,因此您可以从其继承并创建接口:

public class FileSystemWatcherWrapper : FileSystemWatcher, IFileSystemWatcherWrapper
    {
      //empty on purpose, doesnt need any code
    }

 public interface IFileSystemWatcherWrapper
    {
        event FileSystemEventHandler Created;
        event FileSystemEventHandler Deleted;
        bool EnableRaisingEvents { get; set; }

        bool IncludeSubdirectories { get; set; }

        string Path { get; set; }
        string Filter { get; set; }

        void Dispose();
    }
}

然后您可以使用Mock by Mock进行单元测试