如何测试委托方法

时间:2010-11-12 18:32:11

标签: c# unit-testing

我在一个类中有一个简单的方法,它负责在appconfig.xml中给定某个路径注册FileSystemWatcher:

public void ListenPath(string path){
    //path validation code
    //...

    FileSystemWatcher objFileWatcher = new FileSystemWatcher();
        objFileWatcher.Path = path;
        objFileWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
       | NotifyFilters.FileName | NotifyFilters.DirectoryName;
        objFileWatcher.Filter = "*.txt";
        objFileWatcher.Created += new FileSystemEventHandler(ProcessInput);
        objFileWatcher.EnableRaisingEvents = true;
}

在我的单元测试中,我必须声明:

1)提供错误或空路径应该引发PathNotFoundException

2)正确注册了ProcessInput方法,以便在创建文件时监听“path”。

如何执行第2项的单元测试?

非常感谢

3 个答案:

答案 0 :(得分:1)

在事件上注册回调只是填充变量。它或多或少地将回调添加到回调列表中。我通常不会验证附带的东西,例如列表的填充,除非数据填充是类的整个点(就像类表示自定义数据结构一样)。

您可以改为在修改指定文件时验证是否调用了ProcessInput。有几种方法可以解决这个问题:

  • 测试ProcessInput的副作用,例如它填充了程序中的其他结构或属性
  • ProcessInput方法分离到另一个类或接口。引用此类型作为ListPath的参数,或类的构造函数。然后模拟那种类型

模拟对象示例:

public interface IInputProcessor
{
    void ProcessInput(Object sender, FileSystemEventArgs e);
}

public class ClassUnderTest
{
    public ClassUnderTest(IInputProcessor inputProcessor)
    {
        this.inputProcessor = inputProcessor;
    }

    public void ListenPath(string path){
        // Your existing code ...
        objFileWatcher.Created +=
            new FileSystemEventHandler(inputProcessor.ProcessInput);
        // ...
    }

    private IInputProcessor inputProcessor;
}

public class MockInputParser : IInputProcessor
{
    public MockInputParser()
    {
        this.Calls = new List<ProcessInputCall>();
    }

    public void ProcessInput(Object sender, FileSystemEventArgs args)
    {
        Calls.Add(new ProcessInputCall() { Sender = sender, Args = args });
    }

    public List<ProcessInputCall> Calls { get; set; }
}

public class ProcessInputCall
{
    public Object Sender;
    public FileSystemEventArgs Args;
}

[Test]
public void Test()
{
    const string somePath = "SomePath.txt";
    var mockInputParser = new MockInputParser();
    var classUnderTest = new ClassUnderTest(mockInputParser);
    classUnderTest.ListenPath(somePath);
    // Todo: Write to file at "somePath"
    Assert.AreEqual(1, mockInputParser.Calls.Count);
    // Todo: Assert other args
}

答案 1 :(得分:0)

如果FileSystemWatcher是您有权访问的内容,则可以对其进行设置,以便模拟Created事件的触发。但我怀疑它不是,这意味着你已经达到了真正的“单元测试”并不容易的地步。

您可以尝试使用像TypeMock或Moles这样的隔离器来模拟Created事件的触发。但最简单的事情可能是实际编写一个在给定路径上创建文件的测试,并确保在发生这种情况时调用ProcessInput方法。

因为您没有在ProcessInput本身周围显示定义或任何其他代码,所以我不知道确保调用它的最佳方法。

答案 2 :(得分:0)

您可以将方法拆分为两个:第一个方法只是实例化,配置并返回FileSystemWatcher的一个实例。然后,您可以轻松地测试返回的结果对象。第二种方法可以将其作为参数,并简单地在其上启用上升事件。