BDD style specs with NUnit

by Scott MIllett 5. February 2011 00:14

I thought I would kick off my first post  with how I have been using NUnit with BDD style syntax, specifically the Given, When, Then acceptance test template.

Lets take a look at an example based on the following user story and acceptance criteria scenario..

In order to get a discounted basket total
As a customer
I want to apply a voucher

Given I have added the following products:
         1 of  Hat @ 20.00
When I apply a voucher with a value of 10.00
Then my basket total should be 10.00

Got it? Ok here's the code...

public class when_applying_a_voucher_to_a_basket : using_a_<Basket>
    {
        private decimal total_before_discount;
        private Voucher voucher;

        public override void Given()
        {            
            voucher = stub_a<Voucher>();
            voucher.Stub(v => v.value).Return(10m);

            var product = stub_a<Product>();
            product.Stub(p => p.price).Return(20m);
                
            system_under_test.add(product);
            total_before_discount = system_under_test.total;
        }

        public override void When()
        {            
            system_under_test.apply_discount(voucher);
        }

        [Then]
        public void the_basket_total_should_be_discounted_by_the_value_of_the_voucher()
        {
            var expected_total = total_before_discount - voucher.value;

            Assert.That(system_under_test.total, Is.EqualTo(expected_total));
        }
    }

You should be able to read the NUnit spec as easy as the scenario - thats the idea anyway. Following are the supporting classes and a brief description of how it all hangs together.

    public abstract class using_a_<SUT> : SpecificationBase
    {
        protected SUT system_under_test;

        public using_a_()
        {
            system_under_test = default(SUT);
        }
    }

    public abstract class SpecificationBase
    {
        [SetUp]
        public void Setup()
        {
            Given();
            When();
        }

        public abstract void Given();

        public abstract void When();        
    }

    public class ThenAttribute : TestAttribute { }

Ok first off is the ThenAttribute class, this is just NUnit syntactic sugar to make the specification read a little better i.e. using [Then] rather than decorating the spec with the default [Test] attribute (line 23 in the first code section) - thanks to Julian H for finding that gem.

Next we have a SpecificationBase class that implements the template method design pattern to define the skeleton of the scenario, this is used as a Layer Supertype for all specifications.

The oddly named using_a_<SUT> class simply creates the SUT (System under test) for me. For types that do not have paramterless constructors I just create a specific base class and expose the dependencies via protected properties.

Finally we have the when_applying_a_voucher_to_a_basket class which contains the actual spec. You can see how the abstract Given and When methods from the SpecificationBase class have been implemented. The Given method sets the context, so in this example that means adding a product to the basket that has a price of 20.00 and creating a voucher that has a value of 10.00. The When method is populated with the code to call the method that is being tested i.e. applying a voucher to a basket. Finally the [Then] decorated method actually asserts what we are expecting - the basket to be discounted by the value of the voucher. The only section of code that might appear odd  is the stub_a<T>() method, which is a just a wrapper for RhinoMocks and lives in the SpecificationBase class, again just a bit of syntactic sugar to make the code read a little better whilst avoiding the RhinoMock set up noise.

Of course there are some great BDD frameworks out there like MSpec and SpecFlow (which I will talk about in a future post), but I like the simplicity of using NUnit. It's a bit wordy and I will probably change my mind next week but for now it will do me just fine.

All the best
Scott

Tags: ,

BDD | NUnit | TDD

Comments (1) -

2/5/2011 12:10:13 PM #

Dave Duffett

Nice one Scott!  We use a very similar (almost identical) approach: "When", "Then" and "Because".  For example:

[TestFixture, TestCategory("Basket")]
public class When_applying_a_voucher_to_a_basket : using_a_<Basket>
{
    [Test]
    public void Then_the_basket_total_should_be_discounted_by_the_value_of_the_voucher()
    {
        // Assertion
    }

    public override void Because()
    {
        // Same as your "Given"
    }
}

Makes the tests very easy to write and also they present well and are easy to understand when run.  We also provide virtual methods for Setup and initialisation of the test subject which can be handy.

Dave Duffett United Kingdom |

Pingbacks and trackbacks (1)+

Comments are closed

About Me

Hello my name is Scott Millett, this is my blog designed to capture my thoughts on development. You can find out more info on me by checking out my linked in profile below.

View Scott Millett's profile on LinkedIn

Coming soon...

Awards

MVP Logo

ASP.NET MVP
2010-2011

Month List

Powered by BlogEngine.NET 2.0.0.36 - Eco Theme by n3o Web Designers