EventAggregator_Mocker is a helper library for writing unit tests with Prism's EventAggregator and Moq. It allows you to verify that an event has been published with the correct parameters and that it was handled in the correct way.
You'll get extension methods for Mock<IEventAggregator>
and Mock<TEvent>
(where TEvent
extends PubSubEvent
or PubSubEvent<T>
)
In your unit test setup instantiate a mock of IEventAggregator.
var eventAggregatorMock = new Mock<IEventAggregator>();
Call one of the extension methods on the IEventAggregator and store the returned mocked event in a variable.
Without parameter:
Mock<MyEvent> mockedEvent = eventAggregatorMock.RegisterNewMockedEvent<MyEvent>();
...
mockedEvent.Verify(evt => evt.Publish(), Times.Once);
With paramater:
Mock<MyParamEvent> mockedParamEvent = eventAggregatorMock.RegisterNewMockedEvent<MyParamEvent, MyParam>();
...
mockedParamEvent.Verify(evt => evt.Publish(It.IsAny<MyParam>()), Times.Once);
We need to get a reference to the event handler, so we can invoke it manually and verify its behavior. We do this by storing this reference in a variable of type Action
or Action<T>
.
The 2 extension methods I used above return an object of type Mock<TEvent>
. On this object, we call another extension method SetSubscribeCallback<TEvent>(Action<Action> onSubscribe)
. This method takes an Action
as a paramater that will recieve a reference to the event handler that will be passed in the Subscribe
method of the actual code we're testing.
So at this point we can store this reference in a variable and invoke it in our unit test. This works even if the method passed is private.
If this sounds a bit complicated, here's an example:
Without parameter:
Action onEventPublishedAction; // This will keep a reference of the event handler that our production code passes into Subscribe().
// During setup
eventAggregatorMock
.RegisterNewMockedEvent<MyEvent>()
.SetSubscribeCallback<MyEvent>(action => onEventPublishedAction = action);
...
// In the unit test
onEventPublishedAction.Invoke();
// Verify that the code has run correctly
With parameter:
Action<MyParam> onEventPublishedAction;
// During setup
eventAggregatorMock
.RegisterNewMockedEvent<MyEvent, MyParam>()
.SetSubscribeCallback<MyEvent, MyParam>(action => onEventPublishedAction = action);
...
// In the unit test
onEventPublishedAction.Invoke(new MyParam());
// Perform assertions
To see it in action, check out this working example
Since version 1.0 EventAggregator_Mocker supports all optional parameters of IEventAggragator.Subscribe()
.
For example:
eventAggregatorMock
.RegisterNewMockedEvent<MyEvent>()
.SetSubscribeCallback(
action => receivedAction = action,
ThreadOption.BackgroundThread, // ThreadOption
true // keepSubscriberReferenceAlive
);