How do I raise an event when a method is called using Moq?

橙三吉。 提交于 2019-12-19 05:08:38

问题


I've got an interface like this:

public interface IMyInterface
{
    event EventHandler<bool> Triggered;
    void Trigger();
}

And I've got a mocked object in my unit test like this:

private Mock<IMyInterface> _mockedObject = new Mock<IMyInterface>();

I want to do something like this:

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

However it doesn't look like Raise is available on the ISetup interface that gets returned. How do I do this?


回答1:


Your pseudo-code was almost spot on. You needed to use Raises instead of Raise. Check the Moq Quickstart: Events for versions Moq 4.x and you will see where you made the mistake.

_mockedObject.Setup(i => i.Trigger()).Raises(i => i.Triggered += null, this, true);

Here is the snippet form 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);



回答2:


So I figured out what I was doing wrong. I'm going to post the answer here but give the credit to Nkosi because I didn't really ask the question correctly, and he provided a lot of useful information.

With an async method on a mock, you need to first specify that it returns a Task before you can have it trigger events. So in my example (realizing that I should have had Task Trigger(); as the method signature, this is the code I was looking for:

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

Apparently this can be simplified even further in C# 4.6, to this:

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



回答3:


Expanding on SoaperGEM's answer, all methods that return something (no matter the type) must have that return value specified before triggering the event. Since async methods return Task, async methods fall into this category. I have a method that returns a string, and I was trying to figure out why I couldn't trigger the event with the Mock object. Then I tried returning first and it worked just fine.

Taking SoaperGEM's example, and assuming Trigger() returns a string:

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


来源:https://stackoverflow.com/questions/37286783/how-do-i-raise-an-event-when-a-method-is-called-using-moq

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!