Testing a method accepting a delegate with Moq

2019-05-18 17:41发布

问题:

my code is using a component implementing an interface like this

public interface IFoo 
{ 
    void DoSomething(string p1);

    void DoSomething(string p1, Action<string> p2);
}

As of this moment, I'm using the first method, but I plan to move to the second one and I want to keep my coverage as high as possible.

Just that I really don't know how to inspect the delegate or even just setup Moq to mock the interface.

I tried with

mock.Setup(p => p.DoSomething(It.IsAny<string>(), It.IsAny<Delegate>()));
mock.Setup(p => p.DoSomething(It.IsAny<string>(), It.IsAny<Action<string>>()));

but neither will let me build. Any suggestion?

回答1:

The line:

mock.Setup(p => p.DoSomething(It.IsAny<string>(), It.IsAny<Delegate>()));

must not compile becaue DoSomething requires an Action<string>, and Delegate is not implicitly convertible to Action<string>. Your other line:

mock.Setup(p => p.DoSomething(It.IsAny<string>(), It.IsAny<Action<string>>()));

works and is correct!

You can setup only when p2 satisfies some criterion, for example:

mock.Setup(p => p.DoSomething(It.IsAny<string>(),
    It.Is((Action<string> p2) => p2 != null && p2.Target is SomeClass)
    ));

Or you can use CallBack to check things:

mock.Setup(p => p.DoSomething(It.IsAny<string>(), It.IsAny<Action<string>>()))
    .CallBack((string p1, Action<string> p2) =>
    {
        // your code (for example Asserts) here,
        // use p2
    });

Of course, there is a limit to how much you can inspect an Action<string>, but you can see if it is non-null, see if its p2.Target is non-null or has a specific type or equals a given instance, you can see if p2.Method is a known (named) method, or you could use p2.GetInvocationList() if you expect a so-called multicast delegate.