使用Moq实例引发EventHandler <TEventArgs>事件

anh*_*ppe 5 c# unit-testing moq

我有接口

public interface IBar
{

}
Run Code Online (Sandbox Code Playgroud)

和

public interface IFoo
{
    event EventHandler<IBar> MyEvent;
}
Run Code Online (Sandbox Code Playgroud)

和一个班级

public class Foobar
{
    public Foobar(IFoo foo)
    {
        foo.MyEvent += MyEventMethod;
    }

    private void MyEventMethod(object sender, IBar bar)
    {
        // do nothing
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我想用Moq 4对这段精彩的代码进行单元测试:

[Test]
public void MyTest()
{
    Mock<IFoo> foo = new Mock<IFoo>();
    Mock<IBar> bar = new Mock<IBar>();

    Foobar foobar = new Foobar(foo.Object);

    foo.Raise(e => e.MyEvent += null, bar.Object);
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,Foobar.MyEventMethod应该通过加注来调用.发生的事情是我得到一个运行时异常,说明System.Reflection.TargetParameterCountEception {"参数计数不匹配."}.

有趣的是:当我在单元测试中提出以下内容时:

foo.Raise(e => e.MyEvent += null, EventArgs.Empty, bar.Object);
Run Code Online (Sandbox Code Playgroud)

一切都按我的意愿运作.任何人都可以解释为什么呼叫需要三个参数?

谢谢

k.m*_*k.m 6

我假设你使用.NET 4.5.删除了类型约束EventHandler<TEventArgs>,允许您执行以下操作:

event EventHandler<IBar> MyEvent;
Run Code Online (Sandbox Code Playgroud)

哪里IBar只是一些界面.

IN 4.0,约束限制TEventArgs可分配给EventArgs类型,您的代码将无法编译.

由于这个原因(IBar不是衍生自EventArgs),Moq不会将您的事件视为"对应于事件处理程序模式",并将其视为任何其他委托:

// Raising a custom event which does not adhere to the EventHandler pattern
...
// Raise passing the custom arguments expected by the event delegate
mock.Raise(foo => foo.MyEvent += null, 25, true);
Run Code Online (Sandbox Code Playgroud)

这意味着您必须提供所有参数,包括发件人.


Mic*_*han 5

第一个不起作用的原因是EventHandlers具有2个参数(对象发送者,EventArgs args)。

设置模拟时

foo.Raise(e => e.MyEvent += null, EventArgs.Empty, bar.Object);
Run Code Online (Sandbox Code Playgroud)

该e => e.MyEvent += null表达式可以告诉您Moq要引发哪个事件,

以下2个参数是您要使用它的2个参数。

EventArgs.Empty, bar.Object
Run Code Online (Sandbox Code Playgroud)

注意:如果我的记忆正确,那应该是相反的。

当您尝试使用1个参数引发事件(bar.Object)时,Moq会抛出一个异常,说明事件处理程序需要2,因为它使用反射来调用它。

您的第一种情况可以这样写:

public class Foo : IFoo
{
    public event EventHandler<IBar> MyEvent;

    public void OnMyEvent(IBar bar)
    {
        MyEvent(EventArgs.Empty)
    }
}
Run Code Online (Sandbox Code Playgroud)

这会给您带来编译器错误:委托'EventHandler'不接受1个参数

这就是为什么您需要2个参数的原因,因为您需要使用以下参数来调用它:

public class Foo : IFoo
{
    public event EventHandler<IBar> MyEvent;

    public void OnMyEvent(IBar bar)
    {
        MyEvent(this, bar);
    }
}
Run Code Online (Sandbox Code Playgroud)