如何在使用 Moq 调用方法时引发事件?
How do I raise an event when a method is called using Moq?
我有这样的界面:
public interface IMyInterface
{
event EventHandler<bool> Triggered;
void Trigger();
}
我的单元测试中有一个这样的模拟对象:
private Mock<IMyInterface> _mockedObject = new Mock<IMyInterface>();
我想做这样的事情:
// pseudo-code
_mockedObject.Setup(i => i.Trigger()).Raise(i => i.Triggered += null, this, true);
但是在返回的 ISetup
界面上似乎 Raise
不可用。我该怎么做?
您的伪代码几乎是正确的。您需要使用 Raises
而不是 Raise
。检查 Moq Quickstart: Events 版本 Moq 4.x,您将看到哪里出错了。
_mockedObject.Setup(i => i.Trigger()).Raises(i => i.Triggered += null, this, true);
// Raising an event on the mock
mock.Raise(m => m.FooEvent += null, new FooEventArgs(fooValue));
// Raising an event on a descendant down the hierarchy
mock.Raise(m => m.Child.First.FooEvent += null, new FooEventArgs(fooValue));
// Causing an event to raise automatically when Submit is invoked
mock.Setup(foo => foo.Submit()).Raises(f => f.Sent += null, EventArgs.Empty);
// The raised event would trigger behavior on the object under test, which
// you would make assertions about later (how its state changed as a consequence, typically)
// Raising a custom event which does not adhere to the EventHandler pattern
public delegate void MyEventHandler(int i, bool b);
public interface IFoo
{
event MyEventHandler MyEvent;
}
var mock = new Mock<IFoo>();
...
// Raise passing the custom arguments expected by the event delegate
mock.Raise(foo => foo.MyEvent += null, 25, true);
所以我弄清楚我做错了什么。我要 post 在这里回答,但要感谢 Nkosi,因为我没有真正正确地提出问题,他提供了很多有用的信息。
在 mock 上使用异步方法,您需要首先指定它 returns 一个任务,然后才能让它触发事件。所以在我的例子中(意识到我应该有 Task Trigger();
作为方法签名,这是我正在寻找的代码:
_mockedObject.Setup(i => i.Trigger())
.Returns(Task.FromResult(default(object)))
.Raise(i => i.Triggered += null, this, true);
显然这可以在 C# 4.6 中进一步简化为:
_mockedObject.Setup(i => i.Trigger())
.Returns(Task.CompletedTask)
.Raise(i => i.Triggered += null, this, true);
扩展 SoaperGEM 的答案,所有 return 某些东西(无论类型)的方法都必须在触发事件之前指定 return 值。由于异步方法returnTask
,异步方法属于这一类。我有一个 return 是 string
的方法,我试图弄清楚为什么我无法使用 Mock 对象触发事件。然后我先尝试 returning,它工作得很好。
以 SoaperGEM 为例,假设 Trigger()
return 是一个字符串:
_mockedObject.Setup(i => i.Trigger())
.Returns("somestring")
.Raises(i => i.Triggered += null, this, true);
我有这样的界面:
public interface IMyInterface
{
event EventHandler<bool> Triggered;
void Trigger();
}
我的单元测试中有一个这样的模拟对象:
private Mock<IMyInterface> _mockedObject = new Mock<IMyInterface>();
我想做这样的事情:
// pseudo-code
_mockedObject.Setup(i => i.Trigger()).Raise(i => i.Triggered += null, this, true);
但是在返回的 ISetup
界面上似乎 Raise
不可用。我该怎么做?
您的伪代码几乎是正确的。您需要使用 Raises
而不是 Raise
。检查 Moq Quickstart: Events 版本 Moq 4.x,您将看到哪里出错了。
_mockedObject.Setup(i => i.Trigger()).Raises(i => i.Triggered += null, this, true);
// Raising an event on the mock
mock.Raise(m => m.FooEvent += null, new FooEventArgs(fooValue));
// Raising an event on a descendant down the hierarchy
mock.Raise(m => m.Child.First.FooEvent += null, new FooEventArgs(fooValue));
// Causing an event to raise automatically when Submit is invoked
mock.Setup(foo => foo.Submit()).Raises(f => f.Sent += null, EventArgs.Empty);
// The raised event would trigger behavior on the object under test, which
// you would make assertions about later (how its state changed as a consequence, typically)
// Raising a custom event which does not adhere to the EventHandler pattern
public delegate void MyEventHandler(int i, bool b);
public interface IFoo
{
event MyEventHandler MyEvent;
}
var mock = new Mock<IFoo>();
...
// Raise passing the custom arguments expected by the event delegate
mock.Raise(foo => foo.MyEvent += null, 25, true);
所以我弄清楚我做错了什么。我要 post 在这里回答,但要感谢 Nkosi,因为我没有真正正确地提出问题,他提供了很多有用的信息。
在 mock 上使用异步方法,您需要首先指定它 returns 一个任务,然后才能让它触发事件。所以在我的例子中(意识到我应该有 Task Trigger();
作为方法签名,这是我正在寻找的代码:
_mockedObject.Setup(i => i.Trigger())
.Returns(Task.FromResult(default(object)))
.Raise(i => i.Triggered += null, this, true);
显然这可以在 C# 4.6 中进一步简化为:
_mockedObject.Setup(i => i.Trigger())
.Returns(Task.CompletedTask)
.Raise(i => i.Triggered += null, this, true);
扩展 SoaperGEM 的答案,所有 return 某些东西(无论类型)的方法都必须在触发事件之前指定 return 值。由于异步方法returnTask
,异步方法属于这一类。我有一个 return 是 string
的方法,我试图弄清楚为什么我无法使用 Mock 对象触发事件。然后我先尝试 returning,它工作得很好。
以 SoaperGEM 为例,假设 Trigger()
return 是一个字符串:
_mockedObject.Setup(i => i.Trigger())
.Returns("somestring")
.Raises(i => i.Triggered += null, this, true);