Testing C# Code That’s Run as the Result of an Event Being Fired

Or, How to test your Presenter classes

A couple of colleagues and I recently finished up a project for a client that involved a lot of C# code. Our unit testing tools of choice were NUnit and Rhino Mocks. The NUnit choice was a pretty easy one (although there are other platforms out there), but we spent a little more time choosing a mocking library.

Our first choice was NMock, primarily because we had experience using it on previous projects and we knew it could get the job done. Before too long, though, we switched to using Rhino Mocks. The primary reason for the change (if I am remembering correctly) was because of its superior event handling capabilities, and we grew to prefer its explicit use of the record-playback-verify mocking model.

Rhino Mocks was one of the first libraries to directly support event registration and event raising by mocks (at least, it was the first we had used). This was a big advantage over having to add a SubscribeEvent() method to our view and model interfaces and having to use syntactically obscure paradigms to capture and fire the event raisers. With Rhino Mocks we could add public events directly to our interfaces and (fairly) explicitly capture the event raisers.

Here is a simple test that captures the registration of an event and fires that event to exercise the class under test:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[test]
public void test_sendRequestToModel()
{
        MocksRepository mocks = new MocksRepository();
        IView view = mocks.CreateMock<IView>();
        IModel model = mocks.CreateMock<IModel>();

        view.SomeEvent += null;
        IEventRaiser someEventRaiser = LastCall.Constraints(Is.NotNull()).GetEventRaiser();

        new Presenter(mode, view);

        model.ProcessRequest();

        mocks.ReplayAll();
        someEventRaiser.Raise();
        mocks.ReplayAll();
}

Even if you are not familiar with Rhino Mocks, this test is pretty self-descriptive. Only the capturing of the raiser is a bit quizzical, but much less so that what we were doing to capture this same functionality in NMock. Here’s a brief breakdown on what is going on with the event capturing:


view.SomeEvent += null;

This records the expectation that we will attach a listener to the SomeEvent event.


EventRaiser someEventRaiser =

This part is pretty clear – we are storing an event raiser to use later to exercise our class under test.


LastCall.

This is a static object in Rhino Mocks that provides access to the last recorded expectation – in this case the ‘view.SomeEvent += null’ expectation.


Constraints(Is.NotNull()).

One of the things that LastCall allows you to do is to modify the expectation. Here we are setting up an argument constraint that says any argument (other than null) is sufficient. With this constraint it won’t matter what our class under test attaches to the event as a listener – as long as something is.

The Constraints() method returns the mock object recording handler that was modified, so we can daisy chain modifications like so:


GetEventRaiser();

This method uses a little bit of reflection magic to determine which event (if any) was attached to in the last call and creates an object we can use to cause that event to be fired. By storing the return value from this call we can initiate our test later.

The rest is pretty self evident. We create our object under test, set up an expected call to the model method ProcessRequest(), switch from record mode to replay mode, exercise our object by firing the event, and then verify that all expectations have been met.

The production code to make this test pass might look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Presenter ()
{
    private readonly IModel _model;
    private readonly IView _view;

    public Presenter(IModel mode, IView view)
    {
        _model = model;
        _view = view;

        _view.SomeEvent += SendRequestToModel;
    }

    private void SendRequestToModel()
    {
        model.ProcessRequest();
    }
}

Multiple events – Multiple tests

The event capturing and firing features available in Rhino Mock results in a pretty clean and readable test for code that is executed as the result of a firing event. But this simple example hides a couple of issues that arise as the class under test becomes more complicated.

The first issue is actually not much of an issue at all. If our class responds to multiple events, it is relatively simple to set up expectations for each registration:

1
2
3
4
5
6
7
8
9
10
...
view.SomeEvent += null;
IEventRaiser someEventRaiser = LastCall.Constraints(Is.NotNull()).GetEventRaiser();

view.AnotherEvent += null;
IEventRaiser anotherEventRaiser = LastCall.Constraints(Is.NotNull()).GetEventRaiser();

model.StateUpdated += null;
IEventRaiser updateRaiser = LastCall.Constraints(Is.NotNull()).GetEventRaiser();
...

Each event registration gets its own expectation and raiser, no problem there. But it exposes the main issue I’ve been ignoring so far.

Moving setup code into Setup

I have been putting all of the test code into the test method itself. In a real test for a real class you would normally see test set up code in the Setup() method. This neatly separates shared initialization code that is needed for each test. This makes each test method more clear about what is being tested. Here is our revised code using the Setup() method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[SetUp]
public void Setup()
{
        MocksRepository mocks = new MocksRepository();
        IView view = mocks.CreateMock<IView>();
        IModel model = mocks.CreateMock<IModel>();

        view.SomeEvent += null;
        IEventRaiser someEventRaiser = LastCall.Constraints(Is.NotNull()).GetEventRaiser();

        new Presenter(mode, view);
}

[test]
public void test_sendRequestToModel()
{
        model.ProcessRequest();

        mocks.ReplayAll();
        someEventRaiser.Raise();
        mocks.VerifyAll();
}

There. Now my test initialization code is separated from the code that actually tests the functionality of the class. But now we have a problem. We are setting expectations and running the test target code in two separate locations.

Prior to the ‘new Presenter(mode, view)’ line of code in the Setup method, we are in record mode. Creating a new Presenter object exercises our class under test, but to have this run properly, we must first switch to replay mode:

1
2
3
4
...
mocks.ReplayAll();
new Presenter(mode, view);
...

Unfortunately, this leaves us in replay mode when we get to test method, where we are setting up more expectations. We must switch back to replay mode for the tests:

1
2
3
4
5
...
mocks.ReplayAll();
new Presenter(mode, view);
mocks.BackToRecordAll();
...

Of course, we should also verify that all of our expectations up to that point have been met:

1
2
3
4
5
6
...
mocks.ReplayAll();
new Presenter(mode, view);
mocks.VerifyAll();
mocks.BackToRecordAll();
...

So finally, we have a complete Setup method. It has the appropriate expectations, tests and verifications and leaves us in a state to set expectations for each test individually.

Here is the complete setup method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[SetUp]
public void Setup()
{
        MocksRepository mocks = new MocksRepository();
        IView view = mocks.CreateMock<IView>();
        IModel model = mocks.CreateMock<IModel>();

        view.SomeEvent += null;
        IEventRaiser someEventRaiser = LastCall.Constraints(Is.NotNull()).GetEventRaiser();

        mocks.ReplayAll();
        new Presenter(mode, view);
        mocks.VerifyAll();
        mocks.BackToRecordAll();
}

If you had any other expectations from code in the constructor of your class under test, they would be set here (before the ReplayAll call).

This paradigm works, and it is fairly clear what is going on with the mocking library and why. We used this style of test writing for a large portion of the project. We even had a Resharper live temple hooked up to generate the majority of our Setup method for presenters. If you have had any trouble figuring out how to test your presenter classes (or any classes that respond to events) I recommend trying this technique.

Eventually, however, we wondered if there was a better way of factoring out all of the mocking language (ReplayAll, VerifyAll, etc) that appears in every single presenter test. We came up with a few techniques, some of which I am still not 100% sure I like better than this, but those will be the topic of the next blog…

Thanks to Greg Pattison for his help in editing this article

Conversation
  • Peter Jakobs says:

    I’m a bit surprised you say Rhinomocks has superior event handling capabilities when compared with NMock. Although NMock has its limitations, with respect to event handling I actually prefer NMock over Rhinomocks.
    Here is how I would write your example using NMock.

    [SetUp]
    public void Setup()
    {
    mocks = new Mockery();
    view = mocks.NewMock();
    model = mocks.NewMock();

    Expect.Once.On(view).EventAdd(“SomeEvent”, Is.Anything)
    new Presenter(model, view);
    }

    [test]
    public void test_sendRequestToModel()
    {
    Expect.Once.On(model).Method(“ProcessRequest”).With();
    Fire.Event(“SomeEvent”).On(view).With();
    mocks.VerifyAllExpectationsHaveBeenMet();
    }

  • Scott says:

    Thanks, Peter. I did not realize that NMock had this sort of event mocking capabilities. While writing this article I did check the docucmentation on the NMock web site, but I did not find any mention of the EventAdd/Fire.Event functions.

    While this makes NMock better suited for testing code driven by events than I thought it was (perhaps as good as Rhino Mocks), I still prefer Rhino’s method of specifying the events via reflection rather than in strings. This is mostly just a matter of personal choice, however.

  • tivadj says:

    Just another implementation using Moq framework http://code.google.com/p/moq/wiki/QuickStart

    Perhaps it cleaner a bit.

    [Test]
    public void TestPresenterUsingMoq()
    {
    var model = new Mock();
    var view = new Mock();
    new Presenter(model.Object, view.Object);

    // get object which able to fire SomeEvent
    var someEventFirer = view.CreateEventHandler();
    view.Object.SomeEvent += someEventFirer;

    // when view fires event model.ProcessRequest is called
    model.Expect(m => m.ProcessRequest());
    someEventFirer.Raise(EventArgs.Empty);

    model.VerifyAll();
    }

  • Comments are closed.