简体   繁体   中英

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:

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

2) That ProcessInput method was correctly registered to listen to "path" when files are created.

How can I perform the unit test for item 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. A couple ways to go about this:

  • Test side-effects of ProcessInput , eg it populated some other structure or property in your program
  • Separate out the ProcessInput method into another class or interface. Take a reference to this type as an argument to ListPath , or the constructor for the class. 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. 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. 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.

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.

You could split your method into two: the first method simply instantiates, configures and returns an instance of the 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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