Using Syntax Fairy Dust to BDD with NUnit

 Mar 17, 2009  |   Filed under: software development  |   Tags: .NET, BDD, Patterns, TDD, Testing


A project that I'm currently involved in is leaning more towards the BDD style syntax of writing tests. We decided to use NUnit instead of any of the spec frameworks out there because NUnit has a large community and a lot of tools that work well with it.

To accommodate this we added a whole bunch of extension methods that wrap the standard NUnit assertions. Example:

public static object ShouldEqual(this object actual, object expected)
{
    Assert.AreEqual(expected, actual);
    return expected;
}

To be honest I never really liked this. It adds loads of extension methods to all objects making the intelisense list contain a lot of garbage. Looking at how RSpec does this and taking some inspiration from the NUnit Constraint-Based Assert Model I figured out a NUnit syntax sugaring to make it more BDDish. My specifications now look like this:

[Describe]
public class MonkeyDescription
{
    private Monkey monkey;

    [Before]
    public void Before()
    {
        monkey = new Monkey();
    }

    [After]
    public void After()
    {
        monkey = null;
    }

    [Specification]
    public void It_should_be_possible_to_name_the_monkey()
    {
        monkey.Name = "Chunky";

        monkey.Name.Should(Be.EqualTo("Chunky"));
    }
}

To accomplish this I first had to add the extension method Should to all objects.

public static class SpecificationExtensions
{
    public static void Should(this object actual, ISpecificationConstraint constraint)
    {
        constraint.Matches(actual);
    }
}

Most constraints will be implemented using the GenericSpecificationConstraint. But since we are using a interface we can easily add any constraints we can think of that can't be implemented using the GenericSpecificationConstraint.

public interface ISpecificationConstraint
{
    void Matches(object actual);
}

public class GenericSpecificationConstraint : ISpecificationConstraint
{
    private Action<object> _specification;

    public GenericSpecificationConstraint(Action<object> specification)
    {
        _specification = specification;
    }

    public override void Matches(object actual)
    {
        _specification(actual);
    }
}

And then we need some syntax helpers:

public static class Be
{
    public static ISpecificationConstraint EqualTo(object expected)
    {
        return new GenericSpecificationConstraint(actual => Assert.That(actual, Is.EqualTo(expected)));
    }

    //...more more more
}

public static class Match
{
    public static ISpecificationConstraint Pattern(string expected)
    {
        return new GenericSpecificationConstraint(actual => Assert.That(actual, Text.Matches(expected)));
    }

    //...more more more
}

These are just two examples but we could easily create other helpers than Be and Match. Contain would be another useful helper.

The only thing remaining now is the attributes. These are easily "aliased" by inheriting the NUnit attributes.

public class DescribeAttribute : TestFixtureAttribute {}
public class SpecificationAttribute : TestAttribute {}
public class BeforeAttribute : SetUpAttribute {}
public class AfterAttribute : TearDownAttribute {}

I don't know if this is useful but it is a alternative way of making NUNit a little more BDDish. We haven't implemented this on our project yet and I don't know if we will.

My biggest issue with this is getting use to all the parenthesis that a assertion requires, monkey.Name.Should(Be.EqualTo("Chunky")), I guess this is what you get for having mandatory parenthesis.