使用 Moq 实例引发 EventHandler<TEventArgs> 事件
Raise an EventHandler<TEventArgs> event with a Moq instance
我有接口
public interface IBar
{
}
和
public interface IFoo
{
event EventHandler<IBar> MyEvent;
}
和一个class
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);
一切如我所愿。谁能解释为什么调用需要三个参数?
谢谢
我假设您当时使用的是 .NET 4.5。 Type constraint was removed from EventHandler<TEventArgs>
这允许你做这样的事情:
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.
第一个不起作用的原因是 EventHandlers 有 2 个参数(对象发送者、EventArgs args)。
设置模拟时
foo.Raise(e => e.MyEvent += null, EventArgs.Empty, bar.Object);
e => 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);
}
}
我有接口
public interface IBar
{
}
和
public interface IFoo
{
event EventHandler<IBar> MyEvent;
}
和一个class
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);
一切如我所愿。谁能解释为什么调用需要三个参数?
谢谢
我假设您当时使用的是 .NET 4.5。 Type constraint was removed from EventHandler<TEventArgs>
这允许你做这样的事情:
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.
第一个不起作用的原因是 EventHandlers 有 2 个参数(对象发送者、EventArgs args)。
设置模拟时
foo.Raise(e => e.MyEvent += null, EventArgs.Empty, bar.Object);
e => 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);
}
}