[c#] 用Moq模擬延伸方法


1 Answers

我用一個包裝來解決這個問題。 創建一個包裝對象並傳遞你的模擬方法。

參見Paul Irwin的單元測試嘲弄靜態方法 ,它有很好的例子。

Question

我有一個預先存在的接口...

public interface ISomeInterface
{
    void SomeMethod();
}

我用mixin擴展了這個內置...

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

我有一個叫做這個我想測試的類。

public class Caller
{
    private readonly ISomeInterface someInterface;

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

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

和一個測試,我想嘲笑接口並驗證對擴展方法的調用...

    [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();
    }

然而運行這個測試會產生一個異常...

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

我的問題是,是否有一種很好的方式來模擬mixin調用?




當我包裝對象本身時,我喜歡使用包裝器(適配器模式)。 我不確定我會用它來包裝一個擴展方法,它不是對象的一部分。

我使用了Action,Func,Predicate或delegate類型的內部惰性可注入屬性,並允許在單元測試期間注入(交換)該方法。

    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;

然後你調用Func而不是實際的方法。

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

有關更完整的示例,請查看http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/






Related