【问题标题】:Raise an EventHandler<TEventArgs> event with a Moq instance使用 Moq 实例引发 EventHandler<TEventArgs> 事件
【发布时间】:2015-03-19 14:26:21
【问题描述】:

我有接口

public interface IBar
{

}

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

还有一个班级

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

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

现在我想使用 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);
}

据我了解 Foobar.MyEventMethod 应该通过 raise 来调用。发生的情况是我得到一个运行时异常,显示 System.Reflection.TargetParameterCountEception {"Parameter count mismatch."}。

有趣的事情:当我在单元测试中提出以下问题时:

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

一切都如我所愿。谁能解释为什么调用需要三个参数?

谢谢

【问题讨论】:

  • 你能发布一个编译并包含IBar类的示例吗?修复明显的编译错误后,您的示例在 .NET 4.0 和 Moq 4.2 下工作。
  • 抱歉,刚刚破解了它。它没有编译真是令人惊讶 ;-) 现在它应该

标签: c# unit-testing moq


【解决方案1】:

我假设您使用 .NET 4.5。 Type constraint was removed from EventHandler&lt;TEventArgs&gt; 允许你做这样的事情:

event EventHandler<IBar> MyEvent;

IBar 只是某个接口

在 4.0 中,约束将 TEventArgs 分配给 EventArgs 类型,您的代码将无法编译。

因此(IBar 不是源自 EventArgs),Moq 不会将您的活动视为 "corresponding to Event Handler pattern",并将其视为任何其他委托:

// 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);

这意味着您必须提供所有参数,包括sender

【讨论】:

  • 谢谢,很好的回答。确实让人眼前一亮。但是我仍然想念为什么有三个参数,我希望我需要对象发送者 TEventArgs args。
  • @anhoppe:第一个参数用于告诉 Moq 要引发哪个事件,foo =&gt; foo.MyEvent += null -- Moq 将剖析这个Expression 并找出你想要@987654333 @ 待提高。其余的是您的自定义委托(object senderEventArgs args)。
【解决方案2】:

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

当你设置模拟时

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

e =&gt; e.MyEvent += null 是一个表达式,用于告诉Moq 要引发哪个事件,

以下 2 个参数是您要引发它的 2 个参数。

EventArgs.Empty, bar.Object

注意:如果我没记错的话,应该是相反的。

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

你的第一个案例可以这样写:

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

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

这会给你一个编译器错误:Delegate 'EventHandler' does not take 1 arguments

这就是为什么您需要 2 个参数,因为您可以使用以下命令调用它:

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

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

【讨论】:

  • 事件正确完成时不需要发送者参数。见:github.com/Moq/moq4/wiki/Quickstart#events
  • 如果他使用 EventHandler,而不是 EventHandler。我不知道如果 IFoo 是从 EventHandler 继承的,它甚至会起作用,我猜我学到了一些新东西。
  • EventArgs.Empty 对我来说是缺失的部分。谢谢。
猜你喜欢
  • 1970-01-01
  • 2012-09-09
  • 1970-01-01
  • 1970-01-01
  • 2016-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-26
相关资源
最近更新 更多