A little BDD/TDD for all


Not knowing about BDD or TDD in this day in age is quite hard. If you have something to do with code then you have been confronted with the two concepts:

So the question is not if you should adopt the methodology, but how do you introduce the new methodology into your projects. The only correct answer is slow.

I must be honest that when TDD became “mainstream” I did not like it. Because you needed very senior developers that had the mental faculties and years of experience to predict tests for a method before it was actually written and consumed by other parts of the system. Before you start trolling and declaring me for insane hear me out!

Before the time of TDD the predominant structure of unit tests was based on methods. If you don’t believe me check your unit tests from last year. Most probably you will find something like this.

[TestFixture]
public class ClassAFixture
{
  [Test]
  public void MethodName_InputOrEnvironment_ExpectedResult()
  {
    // Prepare

    // Act

    // Assert
  }

  ...
}

For a Queue a test according to recepy would look something like this.

[TestFixture]
public class QueueFixture
{
  [Test]
  public void Enqueue_ValidItemQueued_OneItemInQueue
  {
    // Prepare
    var queue = new Queue<string>();

    // Act
    queue.Enqueue("test");

    // Assert
    Assert.That(queue.Peek(), Is.EquealTo("test"));
  }
}

If we stick to this recepy then this becomes practically impossible for more complex objects. But do not be fooled, TDD does not say that you have to write your unit tests like this. This is one of the many misinterpretations of TDD.

If by now you have not read the links at the top of the post and do not know the difference between BDD and BBQ, then do so now.

If you now combine BDD and TDD you have something that is achievable and even better the customer can write your tests(well not the actual code but their description).

To give a quick example.

The customer comes to you wanting to make an intelligent parachute. And after some talking you define the following requirement:

Given a defective parachute

when altitude drops below 500 meters

then emergency parachute opens

Thinking about objects and methods at this point is quite futile. I don’t say its impossible, but it is by no means trivial. So we have to take another path.

Now is the time when you start looking for tolls that will help you with that. There are some good ones out there. In the .net world I tested three:

But there are times when introducing a new tool is not an option(company policy, unwillingness of coworkers to try something new, it’s Friday,…). So you have to use something that is at your disposal and accepted in the company or the project team. In my case this was nUnit, a keyboard and my mind.

Using those ingredients much is possible but it had to be feasible and usable. So I started experimenting. The first permutation was something like this

[TestFixture]
public class ParachudeFixture
{
  [Test]
  public void GivenADefectiveParachute_WhenAltitudeDropsBelow500_ThenEmergencyParachuteOpens()
  {
    // Test code
  }
}

Looks nice and you can really do it before the actual code is there. But there was a fundamental problem with this approach. The problem is that the setup(given) has to be part of every test case. You can solve this using factories. But that would just be ignoring that you are using nUnit.

So I puled all the setups of one kind together in a separate fixture definition. And there is where I got my final model. So now I have something like this.

[TestFixture]
public class GiveADefectiveParachute
{
  private Parachute parachute;

  [SetUp]
  public void SetUp()
  {
    parachute = new DefectiveParachute();
  }

  [Test]
  public void WhenAltitudeDropsBelow500_ThenEmergencyParachuteOpens()
  {
    // Test code
  }
}

And as an added bonus the test run looks nice in the GUI tool.

Before you run off trying to adapt this to your code STOP and read on. This is by far not an ideal solution and it has it’s drawbacks. But personally it worked for my current project and helped me a lot when I checked if my little peace of software supports a magic feature. And what I noticed is that: when I was refactoring my code It was extremely easy to find and remove or refactor obsolete tests.

As a final word of advice: If you can use a framework for TDD/BDD then by all means do. You do not rewrite nUnit every time you want to write a unit test.

There a many frameworks that work and the three I mentioned are quite good.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s