如何在仅具有setter的接口上模拟委托的提出?

时间:2019-02-15 19:03:31

标签: c# moq

我正在尝试使用Moq来模拟接口,但是我看不到该怎么做。界面如下所示:

public delegate void MyDelegate(int i);

public interface MyInterface
{
    void Method(int i);

    MyDelegate MyDelegate { set; }
}

我正在测试一个组件,该组件将带有此接口的对象作为依赖项。我希望能够在调用该方法时测试在引发委托的情况下的交互,但是我看不到该怎么做。我知道这是一种设计界面的奇怪方法,但是我对此没有控制权。

假设我有一个要测试的类:

class SystemUnderTest
{
    int i = 0;

    readonly MyInterface myInterface;

    public SystemUnderTest(MyInterface myInterface)
    {
        this.myInterface = myInterface;
        this.myInterface.MyDelegate = DelegateHandler;
    }

    public int Run(int input)
    {
        this.myInterface.Method(input);
        return i;
    }

    void DelegateHandler(int i)
    {
        this.i = i;
    }
}

我已经尝试过这样的测试,但是在设置模拟时却给出了异常。 “ ArgumentException:无法找到附加或分离方法Void set_MyDelegate(ConsoleApp1.MyDelegate)的事件。”

static void Main(string[] args)
{
    // Arrange
    Mock<MyInterface> mock = new Mock<MyInterface>();

    mock
        .Setup(m => m.Method(It.IsAny<int>()))
        .Raises(m => m.MyDelegate = null, 5);

    // Act
    var sut = new SystemUnderTest(mock.Object);
    var result = sut.Run(5);

    // Assert
    Trace.Assert(result == 5);
}

2 个答案:

答案 0 :(得分:5)

您可以这么说是通过SystemUnderTest.DelegateHandler局部变量桥接MyDelegate。尝试这样的事情:

MyDelegate del = null;

var mock = new Mock<MyInterface>();
mock.SetupSet(m => m.MyDelegate = It.IsAny<MyDelegate>())
    .Callback<MyDelegate>(d => del = d);
mock.Setup(m => m.Method(It.IsAny<int>()))
    .Callback<int>(i => del.Invoke(i));

然后,实际上,每次调用SystemUnderTest.DelegateHandler时都会调用您的mock.Method方法。

答案 1 :(得分:2)

我认为您的方法的根本缺陷是您试图模拟代码中实际上没有发生的事情-即调用void Method(int i)随后会调用您的委托。您不能将Raises用于事件。

我认为您需要MyInterface的“存根”实现,并且根本不需要使用Moq。这是我通过断言的代码:

using System.Diagnostics;

namespace ConsoleApp4
{
    class Program
    {
        static void Main(string[] args)
        {
            // Arrange
            var stub = new StubOfMyInterface();

            // Act
            var sut = new SystemUnderTest(stub);
            var result = sut.Run(5);

            // Assert
            Trace.Assert(result == 5);
        }
    }

    public delegate void MyDelegate(int i);

    public interface MyInterface
    {
        void Method(int i);

        MyDelegate MyDelegate { set; }
    }

    public class StubOfMyInterface : MyInterface
    {
        public void Method(int i)
        {
            MyDelegate?.Invoke(i);
        }

        public MyDelegate MyDelegate { get; set; }
    }

    class SystemUnderTest
    {
        int i = 0;

        readonly MyInterface myInterface;

        public SystemUnderTest(MyInterface myInterface)
        {
            this.myInterface = myInterface;
            this.myInterface.MyDelegate = DelegateHandler;
        }

        public int Run(int input)
        {
            this.myInterface.Method(input);
            return i;
        }

        void DelegateHandler(int i)
        {
            this.i = i;
        }
    }   
}