first steps into context specification

In my previous post I outlined what I want to blog about over coming posts and how I will model an application using behaviour driven design.
So let's get to it.

First I create a new C# class library project called Plutus.Core. This will hold the domain objects, the presenters and views and will have the specifications right alongside the classes that they test (I don't see any need at this stage to have a separate test assembly).
I add the developwithpassion.bdd library to the solution and reference that from my core project. I also reference MbUnit.Framework.dll and the Rhino.Mocks.dll assemblies.

I'm now ready to begin writing code to support my user stories - I have a list of user stories that I want covered by my application, but in these posts I'll pick them off one at a time.
Here's the first:

"As a user I want to view the current balance so that I can see the amount and date that it was captured."

This story suggests that I need a domain entity to hold a balance and for this to have a date and amount property. At this stage there is no logic for me to write so I will make this a data value object that will be readonly after instantiation.

I create a class to hold the specifications for our new code I will be writing and call it "BalanceSpecification" - the file sits within a "Domain" folder within the Core project.

My first crack at the code is as follows:

using System; 
using developwithpassion.bdd.mbunit; 
using developwithpassion.bdd.mbunit.standard; 
using developwithpassion.bdd.mbunit.standard.observations;

namespace Plutus.Core.Domain 
{ 
    public class BalanceSpecification : observations_for_a_sut_without_a_contract<Balance> 
    { 
        protected static double amount = 1234.50; 
        protected static DateTime date = DateTime.Now; 

        public override Balance create_sut() 
        { 
            return new Balance(amount, date); 
        } 
    } 
}

The BalanceSpecification class will act as a base class for all the "Observations" that I want to make on the domain code that I will be writing. Notice that it inherits from "observations_for_a_sut_without_a_contract" class - this is part of the developwithpassion library and facilitates the wiring up of our tests into the context specification style and AAA pattern of testing.
Under the hood it hooks up the system-under-test (SUT) for me based on the T type declaration - in this case a Balance class.

I am overriding the "create_sut()" method to provide my own implementation of the system under test for use in my observations.
For this code to build I obviously have to create an empty shell Balance class - using Resharper I can easily create the class within the same file with a few keystrokes and work with both classes side by side for the time being. I find this the fastest way of making changes in my code as my observations grow until I decide it is time to pull the Balance class out into its real location - a Balance.cs file.

Now I am ready to make my first observation:

[Observations] 
public class when_a_new_balance_is_created : BalanceSpecification 
{ 
    [Observation] 
    public void should_contain_the_amount_it_was_created_with() 
    { 
       sut.Amount.should_be_equal_to(amount); 
    }
}

The class is decorated with an "ObservationsAttribute" - this is again part of the testing library and inherits from MbUnit TestFixturePatternAttribute. The class name is purposefully expressive with underscores within the name and provides a context for the observations I am making... "when a new balance is created (we want to observe that it conforms to specification)".
The test itself is decorated with "ObservationAttribute" and this is also purposefully expressive in its name - "should conform to specification". Put together they express our intent in a very readable way - "when a new balance is created it should contain the amount it was created with".

The code itself uses a static public member of the base test class called "sut" (system under test). This is of type T obtained from the type declaration in observations_for_a_sut_without_a_contract. In this case the sut member is of type "Balance".
This is perhaps the least expressive part of the test syntax under this library - to an untrained eye "sut" doesn't really mean anything, however after a brief introduction - "it means the system under test, the type that is declared in the specification's class declaration" I think we can live with it and its easily understood. To be frank I haven't been able to think of anything more rewarding that provides more clarity other than a verbose member name like systemUnderTest which is just too long as a prefix to our assertions. So sut it is.

My assertion is made using an extension method that makes the code, again, very readable - "the system under test's Amount should be equal to amount". Compare that to the following non-intuitive standard assertion syntax:

Assert.AreEqual(amount, sut.Amount);

Under the hood this extension method basically wraps the MbUnit assert:

static public void should_be_equal_to<T>(this T actual, T expected) 
{ 
    Assert.AreEqual(expected, actual); 
}

So I have my first observation, it is written with a context in mind, is very readable and is written in the AAA style. Because the behaviour under test is constructor driven I don't really have an "Act" - I only have "Arrange"(in the base class in create_sut) and "Assert" (in my individual observations). In later posts I will hopefully illustrate some more complex arrange and act code, but for now this suits my purpose.

I now fix the compile errors produced by the missing Amount property and have a placeholder implementation of the Balance class as follows:

public class Balance 
{ 
    public Balance(double amount, DateTime date)  { } 

    public double Amount { get { return -1} } 
}

I'm now ready to run the test and because I have Resharper I can use the test runner. I've installed an MBunit plug in for resharper so that it can pick up the [Observations] and [Observation] attributes in the resharper test runner.

I have also mapped a keyboard shortcut to automatically run in the current context - I've mapped this to Alt-T keystrokes and with my cursor in the observation class I hit Alt-T and my test runs in the reshaper runner.
Predictably and correctly the test fails and I now need to implement the code:

public class Balance 
{ 
    private readonly double _amount;

    public Balance(double amount, DateTime date) 
    { 
        _amount = amount; 
    } 

    public double Amount { get { return _amount;} } 
}

When I run the tests again they pass and I can move onto my second observation:

[Observations] 
public class when_a_new_balance_is_created : BalanceSpecification 
{ 
    [Observation] 
    public void should_contain_the_amount_it_was_created_with() 
    { 
        sut.Amount.should_be_equal_to(amount); 
    } 

    [Observation] 
    public void should_contain_the_date_it_was_created_with() 
    { 
        sut.Date.should_be_equal_to(date); 
    } 
}

Again, I put a placeholder in for the date property to enable me to run the test, see it fail and then implement the real code:

public class Balance 
{ 
    private readonly double _amount; 
    private readonly DateTime _date; 

    public Balance(double amount, DateTime date) 
    { 
        _amount = amount; 
        _date = date; 
    } 

    public double Amount { get { return _amount;} } 
    public DateTime Date { get { return _date; } } 
}

The tests pass and I have now completed my first specification with a couple of observations.

In the next few post I will dig deeper into the story and attempt to deliver the functionality in more detail..



0 comments: