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

后端 未结 3 692
被撕碎了的回忆
被撕碎了的回忆 2021-01-03 22:56

I\'ve got an interface like this:

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

And I

相关标签:
3条回答
  • 2021-01-03 23:49

    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);
    
    0 讨论(0)
  • 2021-01-03 23:53

    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);
    
    0 讨论(0)
  • 2021-01-03 23:56

    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);
    
    0 讨论(0)
提交回复
热议问题