Unit-testing FileSystemWatcher: How to programatically fire a changed event?

[亡魂溺海] 提交于 2020-02-01 21:42:26

问题


I have a FileSystemWatcher watching a directory for changes, and when there's a new XML file in it, it parses that file and does something with it.

I have a few sample XML files in my project that I am using for unit-testing purposes for the parser I wrote.

I'm looking for a way to use the sample XML files also to test the FileSystemWatcher.

Is it possible to programatically create an event (somehow involving the XML file) in order to trigger the FSW.Changed event?


回答1:


I think that you are taking the wrong approach here.

You should not try to directly unit test the FileSystemWatcher class (you can't - you have no control on it!). Instead, you can try the following:

1) Write a wrapper class for the FileSystemWatcher class that only delegates its functionality to an instance of FileSystemWatcher. Here's an example with one method and one event, add more members as required:

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; }
    }
}

(Note how the instance of FileSystemWatcher is passed to the class constructor; you could create a new instance on the fly instead when the wrapper is constructed)

2) Extract an interface for the class:

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

//and therefore...

public class FileSystemWatcherWrapper : IFileSystemWatcherWrapper

3) Make your class dependant on the interface:

public class TheClassThatActsOnFilesystemChanges
{
    private readonly IFileSystemWatcherWrapper fileSystemWatcher;

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

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

4) At application initialization time, instantiate your class using any dependency injection engine, or just do poor man's injection:

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

5) Now go ahead and write unit tests for TheClassThatActsOnFilesystemChanges by creating a mock of IFileSystemWatcherWrapper that fires events at your will! You can use any mocking engine for that, for example Moq.

The bottom line:

When you have a dependency on a class that you don't control and/or can't be meaningfully unit tested, write a wrap around it with a proper interface, and depend on the interface. Your wrapper is so thin that it doesn't really hurt if you can't unit test it, while your client classes can now be properly unit tested.




回答2:


Just derive from FileSystemWatcher and add whatever you need to the interface:

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)
    {
    }
}



回答3:


As the FileSystemWatcher is not a sealed class, you can inherit from it and create an interface:

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();
    }
}

Then you can unit test with Moq by Mock



来源:https://stackoverflow.com/questions/33254493/unit-testing-filesystemwatcher-how-to-programatically-fire-a-changed-event

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!