简体   繁体   English

提升EventHandler <TEventArgs> 具有Moq实例的事件

[英]Raise an EventHandler<TEventArgs> event with a Moq instance

I have the interfaces 我有接口

public interface IBar
{

}

and

public interface IFoo
{
    event EventHandler<IBar> MyEvent;
}

and a class 和一个班级

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

    private void MyEventMethod(object sender, IBar bar)
    {
        // do nothing
    }
}

Now I want to unit test this brilliant piece of code using Moq 4: 现在我想用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);
}

From my understanding Foobar.MyEventMethod should be called through the raise. 根据我的理解,Foobar.MyEventMethod应该通过加注来调用。 What happens is that I get a runtime exception that says System.Reflection.TargetParameterCountEception {"Parameter count mismatch."}. 发生的事情是我得到一个运行时异常,说明System.Reflection.TargetParameterCountEception {“参数计数不匹配。”}。

Funny thing: when I Raise the following in the unit test: 有趣的是:当我在单元测试中提出以下内容时:

foo.Raise(e => e.MyEvent += null, EventArgs.Empty, bar.Object);

Everything works as I want it. 一切都按我的意愿运作。 Can anybody explain why three arguments are needed for the call? 任何人都可以解释为什么呼叫需要三个参数?

Thank you 谢谢

I assume you use .NET 4.5 then. 我假设你使用.NET 4.5。 Type constraint was removed from EventHandler<TEventArgs> which allows you to do something like this: EventHandler<TEventArgs>删除了类型约束 ,允许您执行以下操作:

event EventHandler<IBar> MyEvent;

Where IBar is just some interface . 其中IBar只是一些界面

IN 4.0, with constraint restricting TEventArgs to be assignable to EventArgs type, your code wouldn't compile. IN 4.0,约束限制TEventArgs可以赋值给EventArgs类型,您的代码将无法编译。

As a result of this ( IBar not deriving from EventArgs ), Moq doesn't consider your event as "corresponding to Event Handler pattern" , and treats it as any other delegate: 由于这个原因( 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);

Which means you have to provide all parameters, including sender . 这意味着您必须提供所有参数,包括发件人

The reason the first is not working because EventHandlers have 2 parameters (object sender, EventArgs args). 第一个不起作用的原因是因为EventHandlers有2个参数(对象发送者,EventArgs args)。

When you are setting up mocking 当你设置嘲笑

foo.Raise(e => e.MyEvent += null, EventArgs.Empty, bar.Object);

the e => e.MyEvent += null is an expression to tell Moq which event to raise, e => e.MyEvent += null是一个告诉Moq要引发哪个事件的表达式,

The following 2 parameters are the 2 arguments you want to raise it with. 以下2个参数是您要引发它的2个参数。

EventArgs.Empty, bar.Object

Note: If memory serves me right, those should be the other way around. 注意:如果记忆对我有用,那应该是另一种方式。

When you try to raise an event with 1 argument ( bar.Object ) Moq throws an exception saying that event handler requires 2 as it uses reflection to invoke it. 当您尝试使用1参数( bar.Object )引发事件时, Moq会抛出一个异常,说事件处理程序需要2,因为它使用反射来调用它。

Your first case could be written like this: 你的第一个案例可以这样写:

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

    public void OnMyEvent(IBar bar)
    {
        MyEvent(EventArgs.Empty)
    }
}

Which gives you a compiler error: Delegate 'EventHandler' does not take 1 arguments 这给你一个编译错误:委托'EventHandler'不带1个参数

So that's why you need 2 parameters, as you would invoke it with the following: 这就是为什么你需要2个参数,就像你用以下方法调用它一样:

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

    public void OnMyEvent(IBar bar)
    {
        MyEvent(this, bar);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM