Three simple Rhino Mocks rules


In previous versions of Rhino Mocks, the Record/Replay model was the only way to create and verify mocks.  You would have an area that set up expectations in a record mode, then the replay mode would verify your expectations.  What was really strange about the Record/Replay model was that it didn’t vibe with the “Setup, Exercise, Verify” unit test pattern.  It looked like you had verifications in the middle of your setup, and your verification was just one line of code, “VerifyAll”.  In addition, you had to decide what kind of test double you wanted when you created it.  Last time I checked, there were at least four choices, and I’ll never get any of them straight on what exactly they did differently.

With the new release of Rhino Mocks 3.5, which RTM’d today, the new Arrange, Act, Assert syntax makes it dirt simple to create test doubles for our unit tests.  In fact, I only really abide by three rules for 99.99% of the mocking cases I run into.  All I need to do is abide by three rules:

  1. Use the static MockRepository.GenerateMock method.  Don’t use an instance of a MockRepository, and don’t use the GenerateStub method.
  2. If the mocked instance method returns a value, use the Stub method to set up a result for that value.  This is an indirect input.
  3. If the mocked instance method does not return a value (void), use the AssertWasCalled/AssertWasNotCalled methods.  This is an indirect output.

That’s it.  I rarely, almost never, assert a method was called on a method that returns a value.  The assumption is that indirect inputs should be used to alter the control flow in the application, or to be observed later in indirect or direct outputs.  When I started using Rhino Mocks, I set expectations on every single method call.  This led to brittle tests, where the body of the test matched almost exactly the implementation.  It was ridiculous.

Here’s an example of snippet of code we want to test (yes it was test-driven the first time I wrote it):

public class OrderProcessor
{
    private readonly ISmtpClient _client;
    private readonly IOrderSpec _spec;

    public OrderProcessor(ISmtpClient client, IOrderSpec spec)
    {
        _client = client;
        _spec = spec;
    }

    public void PlaceOrder(Order order)
    {
        if (_spec.IsMatch(order))
        {
            string body = "Huge frickin' order alert!!!rnOrder #:" + order.OrderNumber;

            MailMessage message =
                new MailMessage("[email protected]", "[email protected]",
                                "Order processed", body);

            _client.Send(message);
        }

        order.Status = OrderStatus.Submitted;
    }
}

Let’s create a test that ensures that when the order specification is a match, we send a message to the SmtpClient:

[Test]
public void Should_send_an_email_when_the_order_spec_matches()
{
    // Arrange
    var client = MockRepository.GenerateMock<ISmtpClient>();
    var spec = MockRepository.GenerateMock<IOrderSpec>();
    var order = new Order {Status = OrderStatus.New, Total = 500m};

    spec.Stub(x => x.IsMatch(order)).Return(true);

    var orderProcessor = new OrderProcessor(client, spec);

    // Act
    orderProcessor.PlaceOrder(order);

    // Assert
    client.AssertWasCalled(x => x.Send(null), opt => opt.IgnoreArguments());
    order.Status.ShouldEqual(OrderStatus.Submitted);
}

I set up the IOrderSpec to return true for IsMatch.  After exercising the OrderProcessor, I ensure that the Send method was called, ignoring any arguments set.  I could have asserted individual parameters, but that’s beyond the scope of this discussion.  What I don’t assert is that the IsMatch method was called.  I don’t care.  If the IsMatch method isn’t called, the Send method won’t be called.  I’ll have more tests to cover the other situations, which will cover all my behavioral specifications I want on the OrderProcessor.

I should also note that I could care less what the GenerateMock method was named.  It could be called GenerateFloogle for all I care, all I’m interested in is how I use the Floogle.  Or Test Double, it doesn’t matter.  I just want a test double, I’ll decide how to use it.  The nice thing about the Rhino Mocks AAA syntax is that I can explicitly setup and verify whatever I want, and the test will fail if I don’t.  I don’t stub properties any more, as I don’t really have any interfaces with properties at this point.  Interfaces are for the most part stateless services, so I don’t need any fancy auto-property behavior for stubs.

Sticking with these three rules for the 99% cases ensures I have good dependency interfaces that conform well to the command/query separation, that method should either perform an operation and return void, or query an object and not change anything.  With the new AAA syntax and these rules, I’ve found my tests to be far less brittle, and much more expressive in describing the behavior I’m specifying.

Transitioning between consulting projects