我有一个FileSystemWatcher
正在监视一个目录的变化,当有新的XML文件出现时,它会解析该文件并对其执行某些操作。
我在项目中有一些样本XML文件,我正在使用它们来进行我编写的解析器的单元测试。
我正在寻找一种方法,可以使用这些样本XML文件来测试FileSystemWatcher
。
是否有可能通过编程方式创建一个事件(与XML文件有关)以触发FSW.Changed
事件?
我有一个FileSystemWatcher
正在监视一个目录的变化,当有新的XML文件出现时,它会解析该文件并对其执行某些操作。
我在项目中有一些样本XML文件,我正在使用它们来进行我编写的解析器的单元测试。
我正在寻找一种方法,可以使用这些样本XML文件来测试FileSystemWatcher
。
是否有可能通过编程方式创建一个事件(与XML文件有关)以触发FSW.Changed
事件?
我认为你在这里采取了错误的方法。
你不应该尝试直接对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; }
}
}
(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)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。
核心要点:
当您依赖于一个无法控制或无法进行有意义单元测试的类时,请编写一个适当接口的包装器,并依赖于该接口。尽管您的包装器非常轻巧,如果不能进行单元测试,也不会对其产生太大影响,而客户端类现在可以得到适当的单元测试。
FileSystemWatcherWrapper
添加公共方法来触发事件。 - Konamiman由于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();
}
}
只需从 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)
{
}
}