简体   繁体   English

如何测试委托方法

[英]How to test a delegated method

I have a simple method in a class that is responsible to register a FileSystemWatcher given a certain path in appconfig.xml: 我在类中有一个简单的方法,负责在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;
}

In my unit test I have to assert: 在单元测试中,我必须断言:

1) Giving a wrong or null path it should raise an PathNotFoundException 1)给出错误或空路径将引发PathNotFoundException

2) That ProcessInput method was correctly registered to listen to "path" when files are created. 2)该ProcessInput方法已正确注册以在创建文件时侦听“路径”。

How can I perform the unit test for item 2? 如何执行项目2的单元测试?

thanks a lot 非常感谢

Registering a callback on an event is simply populating a variable. 在事件上注册回调仅是填充变量。 It's more or less adding a callback to a list of callbacks. 或多或少将回调添加到回调列表中。 I don't generally validate incidental stuff like population of a list, unless data population is the whole point of the class (like if the class represented a custom data structure). 我通常不会验证诸如列表填充之类的偶然事物,除非数据填充是类的整个要点(例如,如果类表示自定义数据结构)。

You can instead validate that ProcessInput gets called when you modify the specified file. 您可以改为在修改指定文件时验证ProcessInput被调用。 A couple ways to go about this: 有几种解决方法:

  • Test side-effects of ProcessInput , eg it populated some other structure or property in your program 测试ProcessInput的副作用,例如,它填充了程序中的其他结构或属性
  • Separate out the ProcessInput method into another class or interface. ProcessInput方法分离到另一个类或接口中。 Take a reference to this type as an argument to ListPath , or the constructor for the class. 引用此类型作为ListPath的参数,或该类的构造函数。 Then mock that type 然后模拟该类型

Mock object example: 模拟对象示例:

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
}

If the FileSystemWatcher is something you have access to, you can set it up so that you can mock the firing of the Created event. 如果您有权访问FileSystemWatcher则可以对其进行设置,以便模拟Created事件的触发。 But I suspect it's not, which means you're getting to the point here where true "unit testing" isn't very easy. 但是我怀疑并非如此,这意味着您到了真正的“单元测试”并非易事的地步。

You could try using an isolator like TypeMock or maybe Moles to simulate the firing of the Created event. 您可以尝试使用诸如TypeMock或Moles之类的隔离器来模拟Created事件的触发。 But the easiest thing might be to actually write a test that creates a file at the given path, and ensure that the ProcessInput method gets called when that happens. 但是最简单的方法可能是实际编写一个在给定路径上创建文件的测试,并确保在发生这种情况时调用ProcessInput方法。

Because you haven't shown the definition or any other code around ProcessInput itself, I don't know the best way to go about ensuring that it got called. 因为您还没有显示ProcessInput本身的定义或任何其他代码,所以我不知道确保调用它的最佳方法。

You could split your method into two: the first method simply instantiates, configures and returns an instance of the FileSystemWatcher. 您可以将方法分为两种:第一种方法仅实例化,配置并返回FileSystemWatcher的实例。 You could then easily test on the returned result object. 然后,您可以轻松地对返回的结果对象进行测试。 A second method could take it as argument and simply enable rising events on it. 第二种方法可以将其作为参数,并仅在其上启用上升事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM