C# 如何在只有setter的接口上模拟委托的提升?

C# 如何在只有setter的接口上模拟委托的提升?,c#,moq,C#,Moq,我试图用Moq来模拟一个界面,但我不知道怎么做。界面如下所示: public delegate void MyDelegate(int i); public interface MyInterface { void Method(int i); MyDelegate MyDelegate { set; } } MyDelegate del = null; var mock = new Mock<MyInterface>(); mock.SetupSet(m =

我试图用Moq来模拟一个界面,但我不知道怎么做。界面如下所示:

public delegate void MyDelegate(int i);

public interface MyInterface
{
    void Method(int i);

    MyDelegate MyDelegate { set; }
}
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));
我正在测试一个组件,该组件将具有此接口的对象作为依赖项。我希望能够测试在调用方法时引发委托的交互,但我看不出如何做。我知道这是一种设计界面的有点奇怪的方式,但我无法控制它

假设我有这样一个类要测试:

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:找不到附加或分离方法无效集\u MyDelegate(ConsoleApp1.MyDelegate)的事件。”

static void Main(字符串[]args)
{
//安排
Mock Mock=新Mock();
嘲弄
.Setup(m=>m.Method(It.IsAny()))
.Raises(m=>m.MyDelegate=null,5);
//表演
var sut=新系统测试(模拟对象);
var结果=sut.Run(5);
//断言
断言(结果==5);
}

我认为您的方法的根本缺陷是您试图模拟代码中实际上没有出现的东西,即调用
无效方法(inti)
之后会调用您的委托。不能使用
提升
,因为这是用于事件的

我认为您需要一个
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;
        }
    }   
}

可以这样说,通过
MyDelegate
局部变量桥接
SystemUnderTest.DelegateHandler
。试着这样做:

public delegate void MyDelegate(int i);

public interface MyInterface
{
    void Method(int i);

    MyDelegate MyDelegate { set; }
}
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));
MyDelegate del=null;
var mock=new mock();
mock.SetupSet(m=>m.MyDelegate=It.IsAny())
.回调(d=>del=d);
mock.Setup(m=>m.Method(It.IsAny()))
.Callback(i=>del.Invoke(i));

然后,实际上每次调用
mock.method

时都会调用
SystemUnderTest.DelegateHandler
方法。这可能对您有所帮助:只说
MyDelegate del=null不是更自然吗声明变量的位置(第一行)。除此之外,我同意你的解决方案;对仅限集合的属性使用
SetupSet
。属性具有委托类型这一事实并不重要。如果属性(此处在
MyInterface
中声明)没有C#
event
关键字,则该属性不是事件;询问者使用的
Raises
是错误的,但是
Callback
是他想要的。@JeppeStigNielsen是的,它也可以是
MyDelegate=null,如果由于某种原因未设置
del
,则最好避免隐藏调用。。。