Nov 16, 2009

Raising Events With Rhino Mocks AAA Syntax

There’s various posts on the web showing how to raise events in Rhino Mocks but they typically show you how to do it using the Record/Replay syntax, which I personally find quite awkward.

I was just helping out someone today and showing them how to do it using the Arrange, Act, Assert (AAA) syntax in Rhino Mocks 3.5 and I thought you might be interested in know how to do this as well.

Let’s start with a basic scenario… let’s assume that in our class under test we wanting to check that when we call a method on another object, that it will raise a CancelEvent and we can listen to that event and take action as appropriate.  I like to test behaviour in my classes, so in my test I want to be sure that my class under test correctly subscribes to the event and that it will set the cancel flag correctly..

Here’s some code.
public interface IProcessor
{
 string AMethodThatRaisesAnEvent(int value);
 event EventHandler<CancelEventArgs> AboutToProcess;
}

public class EventListener
{
    IProcessor processor;
    public EventListener(IProcessor processor)
    {
        this.processor = processor;
        this.processor.AboutToProcess += HandleTheEvent;
    }

    public string MakeItHappen()
    {
        return processor.AMethodThatRaisesAnEvent(0);
    }

    public void HandleTheEvent(object sender, CancelEventArgs args)
    {
        if (sender is IProcessor)
        {
            args.Cancel = true;
        }
        return;
    }
}
So as we can see, the constructor takes in the processor object and starts listening for the AboutToProcess event.  When it fires it checks the senders type and and sets the Cancel flag.  It’s a silly thing to do in reality since normally you would check property values on the sender and decide wether to cancel or not, but for the purposes of the post, it will do.

Now let’s write our behaviour test.
[Test]
public void TheEventListenerShouldCauseProcessingToBeCancelled()
{
    var processor = MockRepository.GenerateStub<IProcessor>();
    var args = new CancelEventArgs();
    var listener = new EventListener(processor);
    processor.Stub(p => p.AMethodThatRaisesAnEvent(0)).IgnoreArguments()
        .Do(new Func<int , string>(value =>
                {
                    processor.Raise(x => x.AnEvent += null, processor, args);
                    Assert.IsTrue(args.Cancel);
                    return string.Empty;
                }));
    listener.MakeItHappen();
}
So what’s happening here?

In the first few lines we arrange the objects we want for the test, then we get into the juicy bit.

It may look a little scary but if you break it down into it’s components, it’s actually prettty easy to grok.  First we set up a stub for when the AMethodThatRaisesAnEvent() is called.  We ignore any argument values that may be passed into it and we then supply a method implementation using Rhino’s Do() method.

Inside Do we supply a new function that takes an int as a parameter and returns a string – the same signature as the AMethodThatRaisesAnEvent() method that we are stubbing.  Inside it we Raise() the event we want to fire and have an Assert that will check if the Cancel flag has been set to true.  Note that we also need to supply a return value otherwise the code won’t compile.

Look a little closer at the Raise() method.  You’ll see that you don’t just say what event to raise, you actually supply a lambda that subscribes to the event you want to raise.  It looks a little wierd but it’s a workaround for the language limitations.  The second two parameters are the event sender and eventargs parameters.

Finally we make a call on our class under tests MakeItHappen() method.  There’s no asserts aftrer that because we are only wanting to check the event handling behaviour, not the return value from the mock object.  Also, if you set a breakpoint inside the Do method, you’ll see that the event raising happens after the MakeItHappen() call, even though it appears before it in the source.

And there you have it – raising events from mock objects using Rhino Mocks.

P.S. Some of you will have noticed that I’m using Stubs instead of Mocks.  This is because I’m not asserting anything on the fake object itself and I’m simply stubbing out code.  Please don’t get too hung up on this.  There’s a whole world of pointless arguments about what to call fake objects; stubs, mocks, fakes, whatever.  I certainly don’t care and the code works just the same if you use GenerateMock and processor.Expect() so do what you’re comfortable with and ignore the storm in a teacup argument over what to call them.

2 comments:

  1. Hi Richard,

    I tend to try and use WhenCalled() instead of Do() as you don't have to explicitly deal with the Delegate type. You could also consider moving the assertion out of the event raising code, as I think that makes the point of the test a bit clearer.

    [Test]
    public void TheEventListenerShouldCauseProcessingToBeCancelled()
    {
    var processor = MockRepository.GenerateStub<IProcessor>();
    var args = new CancelEventArgs();
    var listener = new EventListener(processor);
    processor.Stub(p => p.AMethodThatRaisesAnEvent(0))
    .IgnoreArguments()
    .Return(string.Empty)
    .WhenCalled(invocation => processor.Raise(x => x.AboutToProcess += null, processor, args));
    listener.MakeItHappen();
    Assert.IsTrue(args.Cancel);
    }

    As an aside, I think it's preferable to avoid mocking this much of the dependency's behaviour where possible. Otherwise when our dependency changes we'll also have to update this test.

    Regards,
    David

    ReplyDelete
  2. @David Thanks for that - I've never actually used WhenCalled before. Not sure how I've missed that in all this time :-/ The code definitely looks cleaner that way.

    ReplyDelete