Arrange Act Assert and BDD specifications

With Rhino Mocks 3.5 just around the corner, I’ve started using it to create much more readable tests.  One of the things that always bothered me with Expect.Call, constraints and the like was that it mixed in the Arrange with Assert.  For those that haven’t heard of AAA, it’s a pattern for authoring unit tests:

  • Arrange – set up the unit under test
  • Act – exercise the unit under test, capturing any resulting state
  • Assert – verify the behavior through assertions

As I moved towards BDD context/specification style tests, working with Rhino Mocks didn’t fit the picture very well.  But with the new AAA syntax of Rhino Mocks 3.5, I can very cleanly separate out the behavior I want to observe from the mechanics of setting up the test.

Here’s a normal unit test, as I would have written it about a year ago:

[Fact]
public void Should_send_email_when_order_is_over_200()
{
    MockRepository repo = new MockRepository();

    //Arrange
    ISmtpClient mockClient = repo.DynamicMock<ISmtpClient>();
    IOrderSpec stubSpec = repo.DynamicMock<IOrderSpec>();
    MailMessage actual = null;

    Order order = new Order();
    order.Total = 201.0m;

    using (repo.Record())
    {
        mockClient.Send(null);

        // Also assert?
        LastCall
            .IgnoreArguments()
            .Do(new Action<MailMessage>(message => actual = message));

        SetupResult
            .For(stubSpec.IsMatch(order))
            .Return(true);
    }

    OrderProcessor pr = new OrderProcessor(mockClient, stubSpec);

    // Act
    pr.PlaceOrder(order);

    // Assert
    actual.ShouldNotBeNull();
    actual.To.Count.ShouldEqual(1);
    actual.To[0].Address.ShouldEqual("salesdude@email.com");

    repo.VerifyAll();
}

It’s a really long test, but the basic idea is that an email needs to be sent out to the sales guy when big orders get placed.  The sales guy wanted to follow up immediately, to try and sell more (we think).  I see many issues with this test:

  • It’s frickin’ huge
  • I can’t tell what the point of it is at first glance
  • It’s really hard to tell what’s being tested

Moving towards the context/specification style, but still with Rhino Mocks improved things somewhat, but it’s still quite awkward:

public class When_placing_a_large_order 
    : ContextSpecification
{
    private MockRepository _repo;
    private OrderProcessor _orderProcessor;
    private Order _order;
    private MailMessage _actual;

    protected override void EstablishContext()
    {
        _repo = new MockRepository();

        ISmtpClient mockClient = _repo.DynamicMock<ISmtpClient>();
        IOrderSpec stubSpec = _repo.DynamicMock<IOrderSpec>();
        _actual = null;

        _order = new Order();
        _order.Total = 201.0m;

        using (_repo.Record())
        {
            mockClient.Send(null);

            // Also assert?
            LastCall
                .IgnoreArguments()
                .Do(new Action<MailMessage>(message => _actual = message));

            SetupResult
                .For(stubSpec.IsMatch(_order))
                .Return(true);
        }

        _orderProcessor = new OrderProcessor(mockClient, stubSpec);
    }

    protected override void Because()
    {
        _orderProcessor.PlaceOrder(_order);
    }

    [Test]
    public void Should_send_the_email_out()
    {
        _actual.ShouldNotBeNull();
    }

    [Test]
    public void Email_sent_should_be_addressed_to_the_sales_guy()
    {
        _actual.To.Count.ShouldEqual(1);
        _actual.To[0].Address.ShouldEqual("salesdude@email.com");
    }

    [Test]
    public void Should_verify_all_expectations()
    {
        _repo.VerifyAll();
    }
}

Again, I have to do some strange things to capture the output, and the record/replay model doesn’t jive well with BDD-style specifications.  I always had this one observation that said, “Should verify all expectations”.  Not very interesting, and not descriptive of the behavior I want to observe.  It doesn’t describe any behavior, just some cleanup assertion for the MockRepository.

Finally, let’s see how the AAA syntax of Rhino Mocks 3.5 clears things up:

public class When_placing_a_large_order 
    : ContextSpecification
{
    private OrderProcessor _orderProcessor;
    private Order _order;
    private ISmtpClient _mockClient;

    protected override void EstablishContext()
    {
        _mockClient = Dependency<ISmtpClient>();
        IOrderSpec stubSpec = Stub<IOrderSpec>();

        _order = new Order();
        _order.Total = 201.0m;

        stubSpec.Stub(x => x.IsMatch(_order)).Return(true);

        _orderProcessor = new OrderProcessor(_mockClient, stubSpec);
    }

    protected override void Because()
    {
        _orderProcessor.PlaceOrder(_order);
    }

    [Test]
    public void Should_send_the_email_to_the_sales_guy()
    {
        _mockClient.Expect(x => x.Send(Arg<MailMessage>.Matches(msg => msg.To[0].Address == "salesdude@email.com")));
    }
}

That’s a lot smaller!  I clearly separate the Arrange (EstablishContext) from Act (Because) and the Assert, which is my actual observation.  To stub the indirect input of the IOrderSpec, I can use the Stub extension method provided by Rhino Mocks 3.5.

But the best aspect of the new AAA syntax is that I can finally create readable specifications that use Rhino Mocks.  Before, all of the noise of the Record/Replay and the MockRepository obscured the intention of the specification.  I had to rely on test spies earlier to capture the output of the ISmtpClient.Send call, as the old constraint model would have mixed in the Assert with the Arrange (i.e., I would have to put the constraints in the record section.  Not pretty.)

I’ve found that without the distractions of the old Rhino Mocks syntax, I can better focus on the behavior I’m trying to observe.  It’s now just one line to set up indirect inputs with stubs, and one line to verify interactions and indirect outputs.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in BDD, Behavior-Driven Development, Tools. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://johnteague.lostechies.com jcteague

    What is in your ContextSpecification base class?

  • http://colinjack.blogspot.com Colin Jack

    @jcteague
    My guess is very little other than a few virtual/abstract methods for subclasses to override e.g. EstablishContext and Because. Thats what mine is like anyway.

    @jimmy
    Nice stuff, I do like it but I still find mocking and BDD pretty hairy especially with MVC where you can have quite a lot of mocking/stubbing to do as you end up with quite a lot of detail specified upfront when establishing the context. Better than before though!

    On a seperate note do you follow the one-mock approach, so lets say there was also an expectatin that at some point on IOrderSpec…would you do that completely seperately in a different test class?

  • http://www.bluespire.com/blogs Rob

    Thanks for the example! It’s nice to see the progression and that clarified some of the confusion I had around the new syntax.

  • http://www.lostechies.com/blogs/joe_ocampo/ Joe Ocampo

    Is ContextSpecification your own base class? Or is it part of ….?

  • http://victorkornov.ru Victor Kornov

    @Joe
    I believe ContextSpecification comes from NBehave. Also, look for it here http://blog.jpboodhoo.com/BDDAAAStyleTestingAndRhinoMocks.aspx

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Joe, Victor and John

    The ContextSpecification comes from a version of NBehave I still haven’t committed to the trunk. I’ll push it out soon after a few more tweaks.

  • http://morten.lyhr.dk Morten Lyhr

    I wrote about Rhino Mocks 3.5 AAA and BDD here:
    http://morten.lyhr.dk/2008/07/doing-bdd-when-expecting-exception.html

  • http://morten.lyhr.dk Morten Lyhr
  • http://dotnetslackers.com/community/blogs/simoneb Simone Busoli

    I think the _client.Expect call should be replaced with _client.AssertWasCalled. Are you sure it’s really verifying it’s been called?

  • http://weblogs.asp.net/jvano joey

    Hrmm I agree with Simone, the last code block with AAA syntax looks off according to the documentation at least

    Since you are creating a “mock” object for the SmtpClient, you need to verify the expectations that you set on it.

    So the arrangement would be:

    [code]

    protected override void EstablishContext()
        {
            _mockClient = Dependency();
            IOrderSpec stubSpec = Stub();
    
            _order = new Order();
            _order.Total = 201.0m;
    
            stubSpec.Stub(x => x.IsMatch(_order)).Return(true);
           
           //expectation up here
          _mockClient.Expect(x => x.Send(Arg.Matches(msg => msg.To[0].Address == "salesdude@email.com")));
            _orderProcessor = new OrderProcessor(_mockClient, stubSpec);
        }
    
        protected override void Because()
        {
            _orderProcessor.PlaceOrder(_order);
        }
    
        [Test]
        public void Should_send_the_email_to_the_sales_guy()
        {
            _mockClient.VerifyAllExpectations();
        }
    
    [/code]
    

    If you wanted the AAA they would both have to be “Stubs” and in the Assert block you can have:

    [Test]
        public void Should_send_the_email_to_the_sales_guy()
        {
           _stubClient.AssertWasCalled(x=>x.Send( ...));
        }
    

    This is coming from reading this post:
    http://ayende.com/Blog/archive/2008/05/16/Rhino-Mocks–Arrange-Act-Assert-Syntax.aspx

    and documentation here:
    http://ayende.com/wiki/Rhino+Mocks+3.5.ashx#Arrange,Act,Assert

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @joey

    Yep, you’re right. We’ve been doing the latter example in practice. I like asserting individual method calls rather than a bunch of expectations.

  • Pingback: Rhino Mocks | My Blog

  • Pingback: BDD: Links, News and Resources (1) « Angel “Java” Lopez on Blog