Using Moq for Unit Testing with Prism EventAggregator

Kristof Berge
The Startup
Published in
4 min readApr 9, 2020

Welcome to the third and final post of our series about using Prism EventAggregator in .NET app development. In the previous two articles, I covered the Publisher-Subscriber pattern and benefits of using EventAggregator, and how to use it on your projects. Now that we’ve learned how to use EventAggregator in our app code, let’s write some unit tests. Unit testing is a vital part of releasing quality software, so we must test how we’ve used EventAggregator. However, it does present a few challenges. The two most important scenarios to test are:

  • Publisher: Verify whether an event was successfully published with the correct parameter (if applicable).
  • Subscriber: Verify whether a received event was correctly handled.

We could use the actual implementation of Prism EventAggregator. EventAggregator has very few dependencies itself, so this would probably work. But there’s a reason we shouldn’t. For a unit test, we want to isolate the code we’re testing from any kind of dependency. If we use the actual EventAggregator, our test will start to look more like an integration test rather than a unit test. So we want to use a mocked IEventAggregator instead. We’ll be using the Moq library for this.

How to test with Moq

Let’s first set up our EventAggregator example. We start with an event, a publisher, and a subscriber.

Our event has a simple string as a parameter:

We publish the event when the user clicks a button:

The subscriber assigns the received text to a public property:

Testing the publisher

Let’s start with the easiest problem: verifying that the event is published with the correct text when the user clicks the button. In other words, our test will have the following structure:

  • Arrange: Set up the required mocks and instantiate the PublisherViewModel.
  • Act: Execute the OnButtonClickedCommand.
  • Assert: Verify that Publish("text to send") was called once.

First, we need to inject a mock of IEventAggregator into our ViewModel’s constructor:

The only method to set up is GetEvent<MyTextEvent>(). This should return an instance of MyTextEvent. We need to verify something on it, so the event also has to be a mock:

Finally, let’s verify if Publish() is called with the correct argument. Our completed test now looks like this:

The first unit test is done. Now on to the next one.

Testing the subscriber

Testing the subscriber part is a bit trickier. Let’s start with a similar structure:

  • Arrange: Set up the required mocks and instantiate the SubscriberViewModel
  • Act: Execute the code that handles the event
  • Assert: Verify that the Text property has the expected value

The problem here is in the Act phase. The event handling code is HandleMyTextEvent(string text). This method is private, so we cannot call it directly. We don’t want to make the method public because we shouldn’t change access modifiers to accommodate testing. We have to find a different approach. Somehow, we need a reference to that private method so we can invoke it manually. Luckily Moq testing provides us with a very useful method that allows us to do just that: Callback().

We start off the same way as the previous test by creating mocks of IEventAggregator and MyTextEvent and setting up the GetEvent<MyTextEvent>() method. Next, we set up MyTextEvent.Subscribe(Action eventHandler). Instead of calling Returns<T>(T value), we call Callback<T>(Action<T> callbackAction).

This Callback method receives an Action that is called whenever the method being set up is called. If the method being set up receives any arguments, those will be passed into the Action as well. In our case, Subscribe() will receive an Action argument, so our callback action will be an Action<Action>. In other words, our callbackAction will receive a reference to the Action that’s passed into Publish() in the constructor of SubscriberViewModel. All we need to do is save that reference so we can invoke it later. This all sounds a bit complicated, so here it is in code:

Unfortunately, this code will throw an exception. Moq can’t setup Subscribe(Action<string> action) because that’s actually an extension method. Instead, we need to set up the method with all of its optional parameters:

Now that we have a reference to the event handler action, we can complete our Act phase. So our complete test will look like this:

Wow, we finally have a working unit test. But that’s a LOT of code. There should be a more elegant way to do this, right? Enter EventAggregator_Mocker.

Nuget package EventAggregator_Mocker

With the magic of refactoring and the miracle of extension methods I made this neat little nuget package. To use it, just add the package to your test project and you’re good to go.

The package contains two extension methods for Mock<IEventAggregator>:

  • Mock<TEvent> RegisterNewMockedEvent<TEvent>() for mocking events without a parameter
  • Mock<TEvent, TParam> RegisterNewMockedEvent<TEvent, TParam>() for mocking events with a parameter

Both of these will return a mocked event that’s already registered within the mocked IEventAggragator.

You’ll also get two extension methods for Mock<TEvent> that take a callback action as parameter:

  • void SetSubscribeCallback<TEvent>(Action<Action> onSubscribe) for mocking events without a parameter
  • void SetSubscribeCallback<TEvent, TParam>(Action<Action<TParam>> onSubscribe) for mocking events with a parameter

Publisher:

Subscriber:

Well, those code blocks are much shorter and more readable. You can find the source code of the package here. If you want to see it in action, there’s a working example. I hope you found this series on Prism EventAggregator useful.

Originally published at https://arctouch.com.

--

--