Mocking Extension Methods with Moq

我怕爱的太早我们不能终老 提交于 2019-11-26 00:59:08

问题


I have a preexisting Interface...

public interface ISomeInterface
{
    void SomeMethod();
}

and I\'ve extended this intreface using a mixin...

public static class SomeInterfaceExtensions
{
    public static void AnotherMethod(this ISomeInterface someInterface)
    {
        // Implementation here
    }
}

I have a class thats calling this which I want to test...

public class Caller
{
    private readonly ISomeInterface someInterface;

    public Caller(ISomeInterface someInterface)
    {
        this.someInterface = someInterface;
    }

    public void Main()
    {
        someInterface.AnotherMethod();
    }
}

and a test where I\'d like to mock the interface and verify the call to the extension method...

    [Test]
    public void Main_BasicCall_CallsAnotherMethod()
    {
        // Arrange
        var someInterfaceMock = new Mock<ISomeInterface>();
        someInterfaceMock.Setup(x => x.AnotherMethod()).Verifiable();

        var caller = new Caller(someInterfaceMock.Object);

        // Act
        caller.Main();

        // Assert
        someInterfaceMock.Verify();
    }

Running this test however generates an exception...

System.ArgumentException: Invalid setup on a non-member method:
x => x.AnotherMethod()

My question is, is there a nice way to mock out the mixin call?


回答1:


You can't "directly" mock static method (hence extension method) with mocking framework. You can try Moles (http://research.microsoft.com/en-us/projects/pex/downloads.aspx), a free tool from Microsoft that implements a different approach. Here is the description of the tool:

Moles is a lightweight framework for test stubs and detours in .NET that is based on delegates.

Moles may be used to detour any .NET method, including non-virtual/static methods in sealed types.

You can use Moles with any testing framework (it's independent about that).




回答2:


I have used a Wrapper to get around this problem. Create a wrapper object and pass your mocked method.

See Mocking Static Methods for Unit Testing by Paul Irwin, it has nice examples.




回答3:


I found that I had to discover the inside of the extension method I was trying to mock the input for, and mock what was going on inside the extension.

I viewed using an extension as adding code directly to your method. This meant I needed to mock what happens inside the extension rather than the extension itself.




回答4:


You can mock a test interface that inherits from the real one and has a member with the same signature as the extension method.

You can then mock the test interface, add the real one to the mock and call the test method in the setup.

Your implementation of the mock can then call whatever method you want or simply check the that the method is called:

IReal //on which some extension method is defined
{
    ... SomeNotAnExtensionMethod(...);
}

ITest: IReal
{
    ... SomeExtensionMethod(...);
}

var someMock = new Mock<ITest>();
Mock.As<IReal>(); //ad IReal to the mock
someMock.Setup(x => x.SomeExtensionMethod()).Verifiable(); //Calls SomeExtensionMethod on ITest
someMock.As<IReal>().Setup(x => x.SomeNotAnExtensionMethod()).Verifiable(); //Calls SomeNotAnExtensionMethod on IReal

Thanks to Håvard S solution in this post for how to implement a mock that supports to interface. Once I found it, adapting it with the test interface and the static method was a cake walk.




回答5:


I like to use the wrapper (adapter pattern) when I am wrapping the object itself. I'm not sure I'd use that for wrapping an extension method, which is not part of the object.

I use an internal Lazy Injectable Property of either type Action, Func, Predicate, or delegate and allow for injecting (swapping out) the method during a unit test.

    internal Func<IMyObject, string, object> DoWorkMethod
    {
        [ExcludeFromCodeCoverage]
        get { return _DoWorkMethod ?? (_DoWorkMethod = (obj, val) => { return obj.DoWork(val); }); }
        set { _DoWorkMethod = value; }
    } private Func<IMyObject, string, object> _DoWorkMethod;

Then you call the Func instead of the actual method.

    public object SomeFunction()
    {
        var val = "doesn't matter for this example";
        return DoWorkMethod.Invoke(MyObjectProperty, val);
    }

For a more complete example, check out http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/



来源:https://stackoverflow.com/questions/2295960/mocking-extension-methods-with-moq

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!