0

我有以下要测试的代码:

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 测试来执行以下操作:

  1. 创建目录
  2. 设置一个DirectoryProcessor
  3. 将一些文件写入目录(通过File.WriteAllText()
  4. 检查DirectoryProcessor.SourceFileChanged在步骤 3 中添加的每个文件是否已触发一次。

我尝试这样做并Thread.Sleep()在第 3 步之后添加,但很难让超时正确。它正确处理了我写入目录的第一个文件,但不是第二个(超时设置为 60 秒)。即使我能让它以这种方式工作,这似乎也是一种糟糕的编写测试的方式。

有没有人有一个很好的解决这个问题的方法?

4

2 回答 2

2

通常,您关心的是测试与文件系统的交互,而无需测试实际执行操作的框架类和方法。

如果在类中引入抽象层,则可以在单元测试中模拟文件系统,以验证交互是否正确,而无需实际操作文件系统。

在测试之外,“真正的”实现调用这些框架方法来完成工作。

是的,理论上你需要对“真正的”实现进行集成测试,但实际上它应该是低风险的,不会有太大的变化,并且可以通过几分钟的手动测试来验证。如果您使用开源文件系统包装器,它可能会包含这些测试,让您高枕无忧。

请参阅如何在 C# 中模拟文件系统以进行单元测试?

于 2012-08-30T20:17:41.387 回答
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();
     }    

我希望这是有帮助的

于 2012-08-30T20:36:24.403 回答