BDD Antipattern: Specs with concealed intent

A great benefit of Behaviour Driven Development (BDD) is that the unit tests become the primary way of documenting the functionality of a system.  In fact, this why in BDD, “tests” are usually referred to as “specifications” or “specs”.  However, developers need to ensure that the intent of their spec is clearly evident and revealed.

Consider, for a moment, the following spec:

Given my test data
When my analysis is run
Then the results should be correct

It’s impossible to draw any conclusions from this about the functionality of the system, without being able to see the implementation details of this spec.  Let’s suppose that the step implementation details are as follows:

[ActionSteps]
public class DataAnlaysisSteps
{
    private AverageCalculator _calculator;

    [BeforeScenario]
    public void SetupContext()
    {
        _calculator = new AverageCalculator();
    }

    [Given("my test data")]
    public void InsertTestData()
    {
        _calculator.RecordValue(10);
        _calculator.RecordValue(20);
    }

    [When("my analysis is run")]
    public void Analyse()
    {
        _calculator.PerformAnalysis();
    }

    [Then("the results should be correct")]
    public void CheckResults()
    {
        Assert.AreEqual(15, _calculator.Result);
    }
}

If you read through this in detail, then you can probably guess that we are testing some code that computes average values.  Now there is no reason that our spec cannot make this clear:

Given my test data
When the average value is computed
Then the average value should be computed correctly

This is certainly an improvement, albeit a small one.  Language in BDD specs is quite important (as I’ve mentioned previously).  However, it’s impossible to extend this spec to test other datasets and it’s still not entirely clear what we mean by “computed correctly”.  Let’s address this:

Given a value of 10
And a value of 20
When the average value is computed
Then it should be 15

With this spec, there is no doubt about its purpose and the expected behaviour of the underlying system.  It’s also easy to see how we could add more specs to validate the behaviour with other datasets.  For those who are interested, the step implementation details are as follows:

[ActionSteps]
public class DataAnlaysisSteps
{
    private AverageCalculator _calculator;

    [BeforeScenario]
    public void SetupContext()
    {
        _calculator = new AverageCalculator();
    }

    [Given("a value of $n")]
    public void RecordData(int n)
    {
        _calculator.RecordValue(n);
    }
    
    [When("the average value is computed")]
    public void Analyse()
    {
        _calculator.PerformAnalysis();
    }

    [Then("it should be $result")]
    public void CheckResult(int result)
    {
        Assert.AreEqual(result, _calculator.Result);
    }
}
April 28 2011

BDD Antipattern: The technical spec (or why geeks need to speak business)

Crash: "What's that sound?"
Buck: "It's the wind, it's speaking to us."
Eddie: "What's it saying?"
Buck: “I don't know…I don't speak wind."
                         from Ice Age: Dawn of the Dinosaurs

BDD is a pretty well-known and well-understood technique in this day and age, and it’s benefits have been described by many (here, here and here, for example).  A number of these benefits hinge on language and communication, and it turns out that these can be quite easily diluted.  Take this specification, for example:

Given my account is in credit
And my card is valid
And the dispenser contains cash
When I request cash
Then my account should be debited
And cash should be dispensed
And my card should be returned

This is highly readable, even though it contains domain-specific terms (“account”, “credit”, “valid”, “card”, “dispenser”).  Consider now this specification, what I call a technical spec:

Given the CreditValidator returns true for my account
And the CardValidator returns true for my card
And the DispenserStatus service returns CashGreaterThanZero
When the DispenserCashRequested event is raised
Then the RecordDebitTransaction of the AccountService should be invoked
And the EjectCash command should be raised on the command broker
And the EjectCard command should be raised on the command broker

While this may be describing the same thing, the wording is technical and tightly coupled to the actual implementation.  Implementation is a technical detail and not a feature of the business process, and in fact it generally changes more frequently than business process.  So this “technical spec” is simultaneously harder to read and more brittle than the spec that was expressed in business language.  Definitely a BDD anti-pattern.

April 12 2011

NBehave v0.5 Released!

 

If your not running the latest builds from the build server, you might want to grab this latest stable for a few new goodies!

Some highlights include .NET 4.0 builds, more gherkin support, an improved console runner and the stable parts of the Visual Studio plugin we have been blogging about. A big thanks to John and Morgan for their hard work on this.

http://nbehave.org/post/3204419084/0-5-released

Happy coding!

Update: Looks like John and myself blogged at the same time, to save your RSS feed two posts we’ve merged Johns post below:

NBehave 0.5 has just been released into the wild.  The full release notes are available here, but there have been changes relating to most aspects of BDD style development:

  • Scenario processing: embedding table data into scenarios; having scenario outlines that get executed multiple times against a set of example data; comments into scenarios; language support
  • Scenario execution: run scenarios through TestDriven.Net; run scenarios from VS2010 using the NBehave plugin; support for config files
  • Scenario development: generate empty step methods using the command line
  • Documentation: more code examples are shipping with the release now
  • Unit test support: the fluent syntax is back, for those devs who want to use NBehave within a unit test framework
  • .Net 4.0 support, as well as .Net 3.5

This is quite a feature-packed release, so I will be posting more details on individual features over time.  For now though, you can grab the download from the Codeplex site.  Note that to get the VS 2010 plugin you will need to download and run the released exe file.  Enjoy!

NBehave alpha now shipping with Should assertion framework

 

It recently came to my attention (when dog-fooding the new version), that I wasn’t able to make any assertions!

Using NBehave without a unit testing framework means we need some other way of checking our results. So I’ve included the Should framework to complete the testing story.

I’m finding it quite a nice framework to use, and its very feature complete. I’ve ILMerged it into the main NBehave.Narrator.Framework assembly, so you don’t need to pull in any references!

Personally I prefer the Fluent API which is quite friendly to intelli-sense, and readability. Here’s an example for a test I’m writing now:

[Then("I should get the available sessions")]
public void ThenIShouldGetTheAvailableSessions()
{
    sessions.Count().Should().Be.GreaterThan(0);
}

You can grab the new version here.

Older Posts