Los Techies : Blogs about software and anything tech!

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!!!\r\nOrder #:" + order.OrderNumber;

            MailMessage message =
                new MailMessage("sender@email.com", "salesdude@email.com",
                                "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.

Kick It on DotNetKicks.com
Posted Oct 05 2008, 10:13 PM by bogardj
Filed under: ,

Comments

Reflective Perspective - Chris Alcock » The Morning Brew #194 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #194
on 10-06-2008 2:05 AM

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #194

Dew Drop - October 6, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - October 6, 2008 | Alvin Ashcraft's Morning Dew
on 10-06-2008 7:30 AM

Pingback from  Dew Drop - October 6, 2008 | Alvin Ashcraft's Morning Dew

chrissie1 wrote re: Three simple Rhino Mocks rules
on 10-06-2008 7:34 AM

Pingback from LessthanDot - VB.Net: Rhino Mocks and the AAA syntax

Three simple Rhino Mocks rules | Survival Food Kits, Tools, Gear wrote Three simple Rhino Mocks rules | Survival Food Kits, Tools, Gear
on 10-06-2008 8:33 AM

Pingback from  Three simple Rhino Mocks rules | Survival Food Kits, Tools, Gear

DotNetKicks.com wrote Three Simple Rhino Mocks Rules
on 10-06-2008 9:00 AM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

FrankM wrote re: Three simple Rhino Mocks rules
on 10-06-2008 1:55 PM

Could please explain a little bit about why don’t use the GenerateStub method? Thanks.

Victor Kornov wrote re: Three simple Rhino Mocks rules
on 10-06-2008 2:00 PM

I'm using Moq not Rhino but... I prefer to obj.VerifyAll() expectations just because that way you know what EXACTLY went wrong. If you do not verify, then you get some NREs. Could be my fault :)

bogardj wrote re: Three simple Rhino Mocks rules
on 10-06-2008 2:38 PM

@FrankM

It's just one less item to worry about.  Whether the object is a stub or not is a function of how I use it (Stub() and AssertWasCalled()).  Always using GenerateMock means I don't have to care.

I also find myself very very rarely creating the Stubs with property-like behavior automatically in there.  Maybe it's the designs I'm working with now, but all my interfaces only have methods, not properties.

@Victor

I can definitely see the benefits of using VerifyAll().  But having the Expect up top isn't AAA any more.  I'm fine with NRE's, but that's just a preference really.  Object Mothers can take care of that issue.

none wrote re: Three simple Rhino Mocks rules
on 10-07-2008 1:24 AM

What are NREs?

2008 October 07 - Links for today « My (almost) Daily Links wrote 2008 October 07 - Links for today &laquo; My (almost) Daily Links
on 10-07-2008 4:30 AM

Pingback from  2008 October 07 - Links for today &laquo; My (almost) Daily Links

bogardj wrote re: Three simple Rhino Mocks rules
on 10-07-2008 6:34 AM

@none

Sorry, "NullReferenceExceptions".  Shoulda called that one out...

Pawel Pabich wrote re: Three simple Rhino Mocks rules
on 10-07-2008 6:41 PM

I might be wrong but as long as you don't set expectations you should use MockRepository.GenerateStub instead of MockRepository.GenerateMock. (ayende.com/.../Rhino+Mocks+3.5.ashx)

bogardj wrote re: Three simple Rhino Mocks rules
on 10-08-2008 6:10 PM

@Pawel

Thanks for the heads up!  That might change my mind on which one I use all the time.  I'd rather _never_ set expectations.

Joe Wilson wrote Comparison of Typemock Isolator and Rhino Mocks
on 10-15-2009 1:55 PM

Comparison of Typemock Isolator and Rhino Mocks

Holy Over Mocking Batman: A Natural Progression « Corey Coogan wrote Holy Over Mocking Batman: A Natural Progression &laquo; Corey Coogan
on 01-28-2010 12:42 AM

Pingback from  Holy Over Mocking Batman: A Natural Progression « Corey Coogan

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Enter the numbers above:
Copyright Los Techies 2008, 2009. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems