Monday, August 27, 2007

Authoring stories with BDD using Behave# and NSpec

A question came up on the Behave# CodePlex site, asking about the intent of Behave# and where it fits with NSpec.  BDD is all about using TDD to create specifications, and NSpec bridges the gap with a specification-friendly API.  For me, the question of when to write Behave# stories and pure NSpec specifications is fairly straightforward.

The stories and scenarios created by the business owner should be captured in Behave# stories and scenarios.  The specifications of everything else should be captured by NSpec (or NUnit.Spec, or NUnit constraints).

But that's not stopping us from using NSpec for the "Then" fragment of a scenario.

Anatomy of a scenario

A scenario is composed of three distinct sections: Context, Event, and Outcome.  The scenario description follows the pattern "Given <context>, When <event>, Then <outcome>.  A sample scenario (and story) could be:

Story: Transfer to cash account

As a savings account holder
I want to transfer money from my savings account
So that I can get cash easily from an ATM

Scenario: Savings account is in credit
	Given my savings account balance is $100
		And my cash account balance is $10
	When I transfer to cash account $20
	Then my savings account balance should be $80
		And my cash account balance should be $30

My outcomes are the "Then" fragment of the scenario, but could also be interpreted as specifications for an account.

Using NSpec with Behave#

So how can we combine NSpec with Behave#?  Here's the story above written with NSpec and Behave#:

Account savings = null;
Account cash = null;

Story transferStory = new Story("Transfer to cash account");

transferStory
    .AsA("savings account holder")
    .IWant("to transfer money from my savings account")
    .SoThat("I can get cash easily from an ATM");

transferStory
    .WithScenario("Savings account is in credit")

        .Given("my savings account balance is", 100, 
                delegate(int accountBalance) { savings = new Account(accountBalance); })
            .And("my cash account balance is", 10, 
                delegate(int accountBalance) { cash = new Account(accountBalance); })
        .When("I transfer to cash account", 20, 
                delegate(int transferAmount) { savings.TransferTo(cash, transferAmount); })
        .Then("my savings account balance should be", 80, 
                delegate(int expectedBalance) { Specify.That(savings.Balance).ShouldEqual(expectedBalance); })
            .And("my cash account balance should be", 30,
                delegate(int expectedBalance) { Specify.That(cash.Balance).ShouldEqual(expectedBalance); })

Note that in the "Then" fragment of the Scenario, I'm using NSpec to specify the outcomes.  By using NSpec and Behave# together to author business owner stories in to executable code, I'm able to combine both the story/scenario side of BDD with the specification side.

3 comments:

Anonymous said...

That's interesting stuff. I hadn't seen NSpec used like that before. As I've been doing an awful lot of WPF recently, I've actually started playing with using XAML as a specification language. It will be interesting to see how it compares with the techniques you use here.

Tim Haughton (NSpec Author)

Anonymous said...

I did some playing around with Behave# too .. looking forward to seeing what other cool things we can do with it in future :)

http://blogs.msdn.com/agilemonkey/archive/2007/08/30/trying-out-behave.aspx

Jimmy Bogard said...

@Tim

We have someone here experimenting with XAML also. The easy object deserialization alone makes it interesting.

@casper
That's an interesting example! I hadn't tried to use Behave# with developer stories. I have a feeling that some of the issues you mentioned would come up a lot with developer stories, as they can be quite technical and not in the ubiquitous language of the business owner.