使用Moq调用方法时如何引发事件?

soa*_*gem 17 c# unit-testing moq

我有这样的界面:

public interface IMyInterface
{
    event EventHandler<bool> Triggered;
    void Trigger();
}
Run Code Online (Sandbox Code Playgroud)

我在我的单元测试中有一个模拟对象,如下所示:

private Mock<IMyInterface> _mockedObject = new Mock<IMyInterface>();
Run Code Online (Sandbox Code Playgroud)

我想做这样的事情:

// pseudo-code
_mockedObject.Setup(i => i.Trigger()).Raise(i => i.Triggered += null, this, true);
Run Code Online (Sandbox Code Playgroud)

但是,在返回RaiseISetup接口上看起来不可用.我该怎么做呢?

Nko*_*osi 19

你的伪代码几乎就是现实.你需要使用Raises而不是Raise.检查Moq快速入门: Moq 4.x版本的事件,您将看到出错的地方.

_mockedObject.Setup(i => i.Trigger()).Raises(i => i.Triggered += null, this, true);
Run Code Online (Sandbox Code Playgroud)

这是GitHub代码片段

// 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);
Run Code Online (Sandbox Code Playgroud)

  • OHHHH,这是一种异步方法。那是我的问题。被称为模拟异步事件时,如何引发事件?(即,它返回Task,而不是void) (2认同)

soa*_*gem 6

所以我弄清楚我做错了什么.我将在这里发布答案,但给予Nkosi的功劳,因为我没有真正正确地提出这个问题,他提供了很多有用的信息.

使用模拟上的异步方法,您需要先指定它返回一个Task,然后才能触发事件.所以在我的例子中(意识到我应该有Task Trigger();方法签名,这是我正在寻找的代码:

_mockedObject.Setup(i => i.Trigger())
    .Returns(Task.FromResult(default(object)))
    .Raise(i => i.Triggered += null, this, true);
Run Code Online (Sandbox Code Playgroud)

显然,这可以在C#4.6中进一步简化,对此:

_mockedObject.Setup(i => i.Trigger())
    .Returns(Task.CompletedTask)
    .Raise(i => i.Triggered += null, this, true);
Run Code Online (Sandbox Code Playgroud)


Jav*_*udt 5

扩展 SoaperGEM 的答案,所有返回某些内容(无论类型)的方法都必须在触发事件之前指定返回值。由于异步方法返回Task,因此异步方法属于此类。我有一个返回 a 的方法string,我试图找出为什么我无法使用 Mock 对象触发事件。然后我尝试先返回,效果很好。

以 SoaperGEM 为例,假设Trigger()返回一个字符串:

_mockedObject.Setup(i => i.Trigger())
    .Returns("somestring")
    .Raises(i => i.Triggered += null, this, true);
Run Code Online (Sandbox Code Playgroud)