Need Quality Code? Get Silver Backed

Given, When, Then - BDD Style Test Framework Part 1

27thJan

0

by Gary H


Program testing can be used to show the presence of bugs, but never to show their absence!

Edsger Dijkstra

Unit Testing, Test Driven Development (TDD) and Behaviour Driven Development (BDD) are all common phrases heard by developers. In this series we will build a framework that will remove a lot of the friction in writing test fixtures. We will use the BDD style Given, When, Then syntax (rather than Arrange, Act, Assert) simply due to personal preference - we think it looks cleaner and gives more readable tests which adds value to the codebase.

Why Unit Test?

In the words of Roy Osherove - "Unit testing, done right, can mean the difference between a failed project and a successful one, between a maintainable code base and a code base that no one dares touch, and between getting home at 2 AM or getting home in time for dinner, even before a release deadline."

Put simply unit testing gives confidence. It gives you confidence that the code that you have written behaves as you expect it to. It gives you freedom to refactor your implementation and remain confident that you didn't break anything.

How we test at Leaping Gorilla

At Leaping Gorilla we prefer a clean BDD style syntax of Given, When, Then. We say Given some preposition, When some behaviour is triggered, Then the outcome should be X,Y,Z. We write our tests using one class per behaviour, each class may contain multiple "Then" assertions. Each of our Then blocks should test only one aspect of the outcome of the behaviour. Lets look at an example.

public class WhenTestingDependencyInjection 
				: WhenTestingTheBehaviourOf
{
    [ItemUnderTest]
    public SimpleClassToTest SimpleClass { get; set; }

    [Dependency]
    public IMockLogger FakeLogger { get; set; }

    [When]
    protected override void When()
    {
        SimpleClass.MethodThatGeneratesALogMessage();
    }

    [Then]
    public void TheFakeLoggerShouldBeCreated()
    {
        Assert.That(FakeLogger, Is.Not.Null);
    }

    [Then]
    public void WeShouldReceiveACallToLog()
    {
        FakeLogger.Received().Log(Arg.Any<string>());
    }

    [Then]
    public void TheSimpleClassShouldBeCreated()
    {
        Assert.That(SimpleClass, Is.Not.Null);
    }
}

This class is a single test for the framework that we will be looking at as part of this article. The name reflects the single behaviour we are testing - dependency injection (DI). We have no "Given" assumptions. In a [Given] block we would normally stub out method calls but this simple example has no dependant calls to worry about. The "When" block invokes the behaviour we are testing. The multiple blocks marked with [Then] attributes are our assertions - each will be picked up as an individual test by the test runner.

The key parts to this example are the attributes and the base class. These are all from the framework we will be looking at.

Writing Testable Code

Stepping back slightly we need to begin by thinking about what makes our code testable. The key feature is decoupling. Decoupling is making each facet of your software independent. Where it needs functionality provided by a different component this should be introduced through Dependency Injection. Lets look at SimpleClass from our example above:

public class SimpleClassToTest
{
    private IMockLogger Log { get; set; }

    public SimpleClassToTest(IMockLogger log)
    {
        Log = log;
    }

    public void MethodThatGeneratesALogMessage()
    {
        Log.Log("Test Message");
    }

    public IMockLogger LogGetter()
    {
        return Log;
    }
}

The simple class uses a logging object. This logger is specified using an interface (not an implementation) and provided through dependency injection via the constructor.

A full discussion about the ins and outs of unit testing is outwith the scope of the article but we highly recommend The Art of Unit Testing by Roy Osherove.

How the Framework Works

Our framework works by finding a single property or field in our test class marked with the [ItemUnderTest] attribute. It then finds all fields or properties marked with a [Dependency] attribute and creates a substitute (a mock) for each of them. It then looks at the available constructors for the item under test and picks the one with the best match to the supplied dependencies. It creates an instance of the item under test injecting the dependency items into the constructor.

With the item under test now created our framework calls the Given method. After this it calls the When method. From here the test framework takes over finding all of our methods marked with [Then] and runs each as its own test, asserting against the results we expect from our When call.

Framework Technology

The framework builds on top of NSubstitute to provide the mocking of dependencies. We use FastMember to provide value writing without the pain of writing our own reflection code for fields and properties. We use NUnit as our backing test framework.

This brings a couple of restrictions due to the technology used but each of them also helps us enforce the need to write testable code.

  • Your item under test must use constructor injection - no dependency attributes will be honoured. This forces us to remove any dependency on a specific DI framework's syntax.
  • Any dependency on which you wish to override the behaviour of a method must be declared as an Interface or the method itself must be virtual. This restriction is imposed by the .Net framework itself and forces us to consider interfaces over concrete type injection.
  • Any field or property that you wish the framework to act upon must be public. This is an implementation preference.

Next Steps

Join us for part two where we will look at the implementation of the framework and start going crazy with reflection in order to automatically build test objects. In the meantime keep an eye on our GitHub page where we will be transitioning all of our Open Source code.

C# , Testing

Comments are Locked for this Post