Как поднять событие при вызове метода с помощью Moq?

У меня есть такой интерфейс:

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

И у меня есть обманный объект в моем unit test, как это:

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

Я хочу сделать что-то вроде этого:

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

Однако это не похоже на то, что Raise доступен в интерфейсе ISetup, который возвращается. Как это сделать?

Ответ 1

Ваш псевдокод был почти точным. Вам нужно использовать Raises вместо Raise. Проверьте Moq Quickstart: События для версий Moq 4.x, и вы увидите, где вы допустили ошибку.

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

Вот фрагмент формы 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

Итак, я понял, что я делаю неправильно. Я собираюсь опубликовать здесь ответ, но даю кредит Нкоси, потому что я действительно не задал вопрос правильно, и он предоставил много полезной информации.

С помощью метода async для макета вам нужно сначала указать, что он возвращает задачу, прежде чем вы сможете инициировать события. Поэтому в моем примере (понимая, что в качестве сигнатуры метода я должен был иметь Task Trigger();, это код, который я искал:

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

По-видимому, это может быть еще более упрощено в С# 4.6, а именно:

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

Ответ 3

Расширяясь в ответе SoaperGEM, все методы, возвращающие что-то (независимо от типа), должны иметь это возвращаемое значение, указанное перед запуском события. Поскольку async методы возвращают Task, методы async попадают в эту категорию. У меня есть метод, который возвращает string, и я пытался выяснить, почему я не мог инициировать событие с помощью объекта Mock. Затем я попытался вернуться первым, и все получилось просто.

Взяв пример SoaperGEM и предположив, что Trigger() возвращает строку:

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