gpt4 book ai didi

c# - 在 C# 中使用 Moq 引发复杂事件

转载 作者:太空狗 更新时间:2023-10-30 01:33:18 25 4
gpt4 key购买 nike

下面的代码应该是不言自明的:我们有一个适配器,它使用来自传输(层)的事件,它持有 MessageRegistrar(对象类型,因为我们无法分辨它的类型,主要是因为这是遗留代码: -))。传输层有一个具体的事件。我想测试触发事件的情况,所以..

在尝试弄清楚为什么它不会通过几个小时后,我提出了以下挑战:

[TestFixture]
public class AdaptorTests
{
public delegate void TracksEventHandler(object sender, List<int> trklst);

public class MyEventHolder
{
public virtual event TracksEventHandler EventName;
}

public interface ITransport
{
object MessageRegistrar { get; }
}

public class MyTransport : ITransport
{
private readonly MyEventHolder m_eventHolder;

public MyTransport(MyEventHolder eventHolder)
{
m_eventHolder = eventHolder;
}

public virtual object MessageRegistrar
{
get { return m_eventHolder; }
}
}

public class MyAdaptor
{
private readonly ITransport m_transport;

public MyAdaptor(ITransport transport)
{
EventTriggered = false;
m_transport = transport;
}

public void Connect()
{
MyEventHolder eventHolder = m_transport.MessageRegistrar as MyEventHolder;
if (eventHolder != null)
eventHolder.EventName += EventHolderOnEventName;
}

private void EventHolderOnEventName(object sender, List<int> trklst)
{
EventTriggered = true;
}

public bool EventTriggered { get; private set; }
}

[Test]
public void test1()
{
Mock<MyEventHolder> eventHolderMock = new Mock<MyEventHolder> {CallBase = true};

Mock<MyTransport> transportMock = new Mock<MyTransport>(eventHolderMock.Object) {CallBase = true};

MyAdaptor adaptor = new MyAdaptor(transportMock.Object);
adaptor.Connect();

MyEventHolder eventHolder = transportMock.Object.MessageRegistrar as MyEventHolder;
Mock.Get(eventHolder).Raise(eh => eh.EventName += null, new List<int>());

Assert.IsTrue(adaptor.EventTriggered);
}

[Test]
public void test2()
{
Mock<MyEventHolder> eventHolderMock = new Mock<MyEventHolder> { CallBase = true };

Mock<MyTransport> transportMock = new Mock<MyTransport>(eventHolderMock.Object) { CallBase = true };

MyAdaptor adaptor = new MyAdaptor(transportMock.Object);
adaptor.Connect();

MyEventHolder eventHolder = transportMock.Object.MessageRegistrar as MyEventHolder;
Mock.Get(eventHolder).Raise(eh => eh.EventName += null, null, new List<int>());

Assert.IsTrue(adaptor.EventTriggered);
}

}

我的问题是:为什么测试(至少其中一个)没有通过?

编辑 @151217-0822 将“adaptor.Connect()”添加到原始帖子(仍然无法解决问题)。

解决方法

感谢@Patrick Quirk:谢谢!!

对于那些遇到相同问题的人:在我了解 Patrick-Quirk 检测到的内容并尝试了几个失败的解决方法之后,我最终添加了以下经过验证的修复程序:'eventHolder.FireEventNameForTestings(new List());':

    public class MyEventHolder
{
public virtual event TracksEventHandler EventName;

public virtual void FireEventNameForTestings(List<int> trklst)
{
TracksEventHandler handler = EventName;
if (handler != null)
handler(this, trklst);
}
}

[Test]
public void test3()
{
Mock<MyEventHolder> eventHolderMock = new Mock<MyEventHolder> { CallBase = true };

Mock<MyTransport> transportMock = new Mock<MyTransport>(eventHolderMock.Object) { CallBase = true };

MyAdaptor adaptor = new MyAdaptor(transportMock.Object);
adaptor.Connect();

MyEventHolder eventHolder = transportMock.Object.MessageRegistrar as MyEventHolder;
eventHolder.FireEventNameForTestings(new List<int>());

Assert.IsTrue(adaptor.EventTriggered);
}

HTH..

最佳答案

似乎 CallBaseRaise() 有一个意想不到的(对我来说)交互。

当您将事件处理程序附加到模拟上的虚拟事件时,您会通过 this code in Moq :

if (invocation.Method.IsEventAttach())
{
var delegateInstance = (Delegate)invocation.Arguments[0];
// TODO: validate we can get the event?
var eventInfo = this.GetEventFromName(invocation.Method.Name.Substring(4));

if (ctx.Mock.CallBase && !eventInfo.DeclaringType.IsInterface)
{
invocation.InvokeBase();
}
else if (delegateInstance != null)
{
ctx.AddEventHandler(eventInfo, (Delegate)invocation.Arguments[0]);
}

return InterceptionAction.Stop;
}

您可以看到,如果 CallBasetrue,那么它会将您的处理程序添加到具体对象的事件(通过 调用.InvokeBase()).如果 CallBasefalse,它将把它添加到 mock 的调用列表中(通过 AddEventHandler)。现在让我们看看the code for Raise() ,它从 Expression 获取事件对象,然后调用 DoRaise() :

internal void DoRaise(EventInfo ev, EventArgs args)
{
// ... parameter validation

foreach (var del in this.Interceptor.InterceptionContext.GetInvocationList(ev).ToArray())
{
del.InvokePreserveStack(this.Object, args);
}
}

看到对 GetInvocationList() 的调用了吗?它从我上面提到的模拟中检索调用列表。此代码从不调用基础对象上的实际事件。

因此,似乎没有办法在 CallBase 设置为 true 的模拟对象上引发事件。

如果您要求 CallBasetrue,我看到的唯一解决方法是向您的具体 MyEventHolder 添加一个方法来触发您的事件.显然,您发布的是一个简化的示例,因此我无法为您提供更多指导,但希望我已经向您展示了为什么您所拥有的内容不起作用。

关于c# - 在 C# 中使用 Moq 引发复杂事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34317702/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com