我有以下代码要测试:
public class DirectoryProcessor
{
public string DirectoryPath
{
get;
set;
}
private FileSystemWatcher watcher;
public event EventHandler<SourceEventArgs> SourceFileChanged;
protected virtual void OnSourceFileChanged(SourceEventArgs e)
{
EventHandler<SourceEventArgs> handler = SourceFileChanged;
if(handler != null)
{
handler(this, e);
}
}
public DirectoryProcessor(string directoryPath)
{
this.DirectoryPath = directoryPath;
this.watcher = new FileSystemWatcher(directoryPath);
this.watcher.Created += new FileSystemEventHandler(Created);
}
void Created(object sender, FileSystemEventArgs e)
{
// process the newly created file
// then raise my own event indicating that processing is done
OnSourceFileChanged(new SourceEventArgs(e.Name));
}
}
基本上,我想编写一个NUnit测试,它将执行以下操作:
DirectoryProcessor
File.WriteAllText()
)DirectoryProcessor.SourceFileChanged
是否针对在步骤3中添加的每个文件触发了一次。我尝试在第3步之后添加Thread.Sleep()
,但很难让超时正确。它正确处理我写入目录的第一个文件,但不是第二个(并且超时设置为60秒)。即使我能以这种方式工作,这似乎是编写测试的一种可怕方式。
有没有人能很好地解决这个问题?
答案 0 :(得分:2)
通常,您关心的是测试与文件系统的交互,而不需要测试实际执行操作的框架类和方法。
如果在类中引入了一个抽象层,则可以在单元测试中模拟文件系统,以验证交互是否正确,而无需实际操作文件系统。
在测试之外,“真正的”实现会调用这些框架方法来完成工作。
是的,从理论上讲,您需要对“真实”实施进行集成测试,但实际上它应该是低风险的,不会有太大的变化,并且可以通过几分钟的手动测试进行验证。如果您使用开源文件系统包装器,它可能包括这些测试,让您高枕无忧。
请参阅How do you mock out the file system in C# for unit testing?
答案 1 :(得分:0)
如果您要测试另一个使用此类的对象,我的答案是无关紧要的。
当我将单元测试写入操作时,我更喜欢使用ManualResetEvent
单元测试将类似于:
...
DirectoryProcessor.SourceFileChanged+=onChanged;
manualResetEvent.Reset();
File.WriteAllText();
var actual = manualResetEvent.WaitOne(MaxTimeout);
...
当manualResetEvent是ManualResetEvent并且MaxTimeout是一些TimeSpan时(我的建议总是使用超时)。 现在我们错过了“onChanged”:
private void onChanged(object sender, SourceEventArgs e)
{
manualResetEvent.Set();
}
我希望这很有用