Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Raising events (from a mock) using Rhino Mocks

I was just asked a question that I thought I would share with everyone in the event that it actually might help anyone else out.

The question was in regards to how (in a unit test) I can have a mock object raise an event when using Rhino Mocks. The particular case in question is to verify that a presenter actually consumes and handles an event published and broadcasted by a view.

Let’s write a test to first encapsulate the requirement that a presenter should subscribe to a particular event of the view interface in the presenters constructor. I have a ReSharper file template that sets me up a MockTestFixture with the following structure: 

using MbUnit.Framework; using Rhino.Mocks; namespace NothinButDotNetStore.Test.Presentation { [TestFixture] public class EmployeeBrowserPresenterTest { private MockRepository mockery; [SetUp] public void Setup() { mockery = new MockRepository(); } [TearDown] public void TearDown() { mockery.VerifyAll(); } } }

I am making use of MbUnit and Rhino Mocks. MbUnit for unit testing and Rhino Mocks as my mock object framework. You’ll notice that I create a MockRepository in the SetUp method and I call VerifyAll in the teardown method. This ensures that I never forget to make the call to VerifyAll as I never need to explicitly call it in any of my test methods.

Let’s get to that first test:

[Test] public void Construction_ShouldSubscribeToEventsOnView() { IEmployeeBrowserView mockView = mockery.CreateMock<IEmployeeBrowserView>(); mockView.Initialize += null; LastCall.Constraints(Is.NotNull()); mockery.ReplayAll(); new EmployeeBrowserPresenter(mockView); }

The 2 most important lines in this test are the following: 

mockView.Initialize += null; LastCall.Constraints(Is.NotNull());

These two lines make up the requirement that:

  • At some point in running this test, the object under test better subscribe to the Initialize event on the view with a Non-Null event handler.

Here is the initial code for the EmployeeBrowserPresenter: 

public class EmployeeBrowserPresenter : IEmployeeBrowserPresenter { private IEmployeeBrowserView view; public EmployeeBrowserPresenter(IEmployeeBrowserView view) { } }

The view interface looks as follows: 

public interface IEmployeeBrowserView { event EventHandler Initialize; }

If I were to run this test right now it would fail, because there is nowhere in the constructor of the presenter that it is subscribing to the events exposed by the view. To get the test running and passing I’ll have to add the following code:

 

public class EmployeeBrowserPresenter : IEmployeeBrowserPresenter { private IEmployeeBrowserView view; public EmployeeBrowserPresenter(IEmployeeBrowserView view) { this.view = view; HookupEventHandlersTo(view); } private void HookupEventHandlersTo(IEmployeeBrowserView view) { view.Initialize += delegate { }; } }

You can see that in the constructor, the presenter now subscribes to the Initialize method with a non null event handler (in this case an empty anonymous method). This gets my test passing. Now I need to write a separate test to verify that the presenter actually does something when the event is raised. Because I will be creating the presenter for each test, each test would need to setup the expecation for the event subscription. I don’t want to duplicate my efforts so I will move some code to the setup method. This will cause my test class to look as follows:

 

[TestFixture] public class EmployeeBrowserPresenterTest { private MockRepository mockery; private IEmployeeBrowserView mockView; [SetUp] public void Setup() { mockery = new MockRepository(); mockView = mockery.CreateMock<IEmployeeBrowserView>(); mockView.Initialize += null; LastCall.Constraints(Is.NotNull()); } [TearDown] public void TearDown() { mockery.VerifyAll(); } [Test] public void Construction_ShouldSubscribeToEventsOnView() { mockery.ReplayAll(); new EmployeeBrowserPresenter(this.mockView); } }

Now I can write the test to ensure that the presenter does something when the view raises its Initialized event. For arguments sake, let’s have the presenter Invoke a method on the view in response to handling the Initialize event:

[Test] public void ViewInitializationHandler_PresenterShouldPushMessageToView() { mockView.DisplayMessage(null); LastCall.Constraints(Is.NotNull()); mockery.ReplayAll(); IEmployeeBrowserPresenter presenter = new EmployeeBrowserPresenter(mockView); IEventRaiser eventRaiser = new EventRaiser((IMockedObject) mockView, "Initialize"); eventRaiser.Raise(null,null); }

Notice how I am leveraging the EventRaiser class to simulate the mock object raising an event. Unfortunately, using this approach defeats the purpose for using Rhino over NMock2 in the sense that you have to resort to providing the name of the event as a string. No good. Let’s refactor this to eliminate the need for the string. I’ll make a change to the Setup method as follows:

private IEventRaiser initializeEventRaiser; [SetUp] public void Setup() { mockery = new MockRepository(); mockView = mockery.CreateMock<IEmployeeBrowserView>(); mockView.Initialize += null; LastCall.Constraints(Is.NotNull()); initializeEventRaiser = LastCall.GetEventRaiser(); }

Using LastCall.GetEventRaiser provides me a way to get access to an event raiser bound to a particular event on a mock object. The caveat is that you have to ensure that the previous mock object expectation (in this call mockView.Initialize += null) was an expectation on an event exposed by the interface. With this IEventRaiser in hand I can refactor my test as follows:

 

[Test] public void ViewInitializationHandler_PresenterShouldPushMessageToView() { mockView.DisplayMessage(null); LastCall.Constraints(Is.NotNull()); mockery.ReplayAll(); IEmployeeBrowserPresenter presenter = new EmployeeBrowserPresenter(mockView); initializeEventRaiser.Raise(null,null); }

The Raise method expects a set of parameters that match up with the signature for the delegate type of the event. In this case the Initialize event on the view interface is an EventHandler delegate type. The EventHandler delegate is the basic event handler signature in the framework that takes a sender and an EventArgs. In this scenario, because my presenter does not care about either, I pass null for both. To get this test to pass I can write the following code on my presenter:

 

private void HookupEventHandlersTo(IEmployeeBrowserView view) { view.Initialize += delegate { view.DisplayMessage(DateTime.Now.ToString());}; }

In the anonymous event handler, I have the presenter invoke the DisplayMessage method on the view, passing it the current time as a string. This satisfies the new requirement in the test:

mockView.DisplayMessage(null); LastCall.Constraints(Is.NotNull());

Now you know how to raise events in a refactorable way using Rhino Mocks.

 

Develop with passion!!

This entry was posted in .Net 2.0, C#, Featured. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

6 Responses to Raising events (from a mock) using Rhino Mocks

  1. Thank you very much for the well written article. I’ve been learning mocking for an MVP web project I’m working on, and this was very helpful.

  2. B-Rain says:

    Maybe a stupid question but what to do if i have multiple events to test. For example Initialize and,say, PostInitialize. How to test it. LastCall contains the last

  3. Joakim says:

    Just in case anyone is still wondering about what using’s are needed:

    using Rhino.Mocks;
    using Rhino.Mocks.Constraints;
    using Rhino.Mocks.Interfaces;

    However it crashed and burned quite well when I tried to run the test :(

    TestCase ‘PresentationLayer.Tests.MainPresenterFixture.Test’
    failed: System.Reflection.TargetParameterCountException : Parameter count mismatch.
    TearDown : System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
    —-> Rhino.Mocks.Exceptions.ExpectationViolationException : IMainView.set_Title(not equal to ); Expected #1, Actual #0.
    ^Anyone know why?

  4. irfan says:

    I downloaded the rhino mock. and tried to test my events.
    But could find the Interface of IEventRaiser.
    What could be the prob.
    the version of DLL is 3.1.0.584

  5. Joshua, thanks for the tip. I usually explicitly call mocker.ReplayAll() in the tests that don’t leverage the MockRepository. This makes it a lot cleaner!!

  6. I picked up a nice tip from the first Hibernating Rhinos episode that Ayende put up: Add mockery.ReplayAll() just before the VerifyAll() in your Teardown. You still want to add the ReplayAll in the appropriate place in your test. Calling it twice does not hurt anything. However, if you fail to call ReplayAll (maybe one of your tests doesn’t use mocks), before calling VerifyAll, it will throw an exception (causing your test to fail).

Leave a Reply