in

 

Jimmy Bogard

Assistant to the assistant to the regional manager

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.

Comments

 

jcteague said:

What is in your ContextSpecification base class?

July 24, 2008 9:15 AM
 

Colin Jack said:

@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?

July 24, 2008 10:02 AM
 

Rob said:

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

July 24, 2008 11:01 AM
 

DotNetKicks.com said:

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

July 24, 2008 12:11 PM
 

Joe Ocampo said:

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

July 24, 2008 2:58 PM
 

Victor Kornov said:

@Joe

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

July 24, 2008 3:45 PM
 

bogardj said:

@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.

July 24, 2008 6:23 PM
 

Reflective Perspective - Chris Alcock » 2008 » July » 25 said:

Pingback from  Reflective Perspective - Chris Alcock  &raquo; 2008 &raquo; July &raquo; 25

July 25, 2008 3:10 AM
 

Morten Lyhr said:

I wrote about Rhino Mocks 3.5 AAA and BDD here:

morten.lyhr.dk/.../doing-bdd-when-expecting-exception.html

July 26, 2008 4:41 AM
 

Morten Lyhr said:

Whoops... wrong url :-)

I wrote about it here:

morten.lyhr.dk/.../doing-bdd-with-rhino-mocks-aaa-syntax.html

July 26, 2008 4:42 AM
 

Andrei Butnaru's blog said:

Programming links, 07.26.2008

July 26, 2008 3:07 PM
 

Link-Listing – July 08 « Cav’s Weblog said:

Pingback from  Link-Listing &ndash; July 08 &laquo; Cav&#8217;s Weblog

July 28, 2008 5:54 PM
 

Simone Busoli said:

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

August 3, 2008 10:42 AM
 

Christopher Bennage said:

Part 0 Part 1 So let&#39;s get back to this whole building a WPF application thing. A number of things

August 16, 2008 8:34 PM
 

Community Blogs said:

Part 0 Part 1 So let&#39;s get back to this whole building a WPF application thing. A number of things

August 16, 2008 9:37 PM
 

Playing with BDD: ContextSpecification said:

Pingback from  Playing with BDD: ContextSpecification

August 26, 2008 7:34 PM
 

Ian Cooper [MVP] said:

Roy has a pretty thoughful post on the barrier to entry for most developers with Test-Driven Development

September 23, 2008 3:17 AM
 

Community Blogs said:

Roy has a pretty thoughful post on the barrier to entry for most developers with Test-Driven Development

September 23, 2008 3:45 AM
 

Mirrored Blogs said:

Roy has a pretty thoughful post on the barrier to entry for most developers with Test-Driven Development

September 23, 2008 4:00 AM
 

joey said:

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]

<pre>

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);

      //expectation up here

     _mockClient.Expect(x => x.Send(Arg<MailMessage>.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]

</pre>

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

<pre>

[Test]

   public void Should_send_the_email_to_the_sales_guy()

   {

      _stubClient.AssertWasCalled(x=>x.Send( ...));

   }

</pre>

This is coming from reading this post:

ayende.com/.../Rhino-Mocks--Arrange-Act-Assert-Syntax.aspx

and documentation here:

ayende.com/.../Rhino+Mocks+3.5.ashx

September 23, 2008 6:22 AM
 

bogardj said:

@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.

September 23, 2008 7:45 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About bogardj

I'm a senior consultant with Headspring Systems in Austin, TX. My focus is using .NET technologies together with Agile methodologies. Back in 2005, I drank the Agile punch and haven't looked at a waterfall the same since.
Copyright Los Techies 2007. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems