exceptionz

Thoughts on Technology, Methodology and Programming.

Archive for September, 2007

Introduce Behavior-Driven Development without much resistance…

Posted by Marcus Wyatt on 17 September 2007

Within the .NET community the idea of test-driven development is starting to become common knowledge. This doesn’t necessarily mean that it is practiced. I believe that although many people find the idea of TDD very easy to grok, they find the implementation of TDD very hard and many revert back to their old ways of working soon after trying TDD.

So why is TDD so hard?

I don’t think that it is only one aspect that makes TDD hard, but a culmination of many factors together. Firstly, you should have a good understanding of OO. You need to understand how to de-couple your objects. How to isolate the class under test by mocking or stubbing the external dependencies. If you are one of those developers that write huge methods with multiple lines of code, then I’m afraid you are not going to be able to practice TDD.

There is also old habits. It is hard to kick old habits, like I can profess when I stopped smoking a couple of years ago. But with perseverance you can loose those old habits.

The other problem is of course the vocabulary you use during a TDD session. All the words you work with has their grounding in validation. i.e. Test, TestFixture, Assert, etc. This makes it quite hard to focus your attention on what you are really doing, specifying the functionality (behavior) of the object. It’s quite simple to see that if I talk about writing a test for the Order object and I assert that the order should be filled, that the language I use isn’t very helpful in making me think about the behavior of the Order. But if I’m writing a specification for the order to specify that an order can be filled, then suddenly my language doesn’t create a barrier.

So what do you mean by ‘introduce BDD without much resistance’?

Wel, in .NET you have the ability to alias and that ability is what I’m using to create an easy why to change the nomenclature of your code. Here is a example of what I’m talking about:

 

    3 using NSpecify.Framework;

    4

    5 using Rhino.Mocks;

    6

    7 using SetupResources = NUnit.Framework.SetUpAttribute;

    8 using DestroyResources = NUnit.Framework.TearDownAttribute;

    9 using Functionality = NUnit.Framework.TestFixtureAttribute;

   10 using Specification = NUnit.Framework.TestAttribute;

   11

   12 [Functionality(Description=“Describe the functionality of the order domain object.”)]

   13 public class OrderFunctionality

   14 {

   15     private MockRepository mockery;

   16     private IWarehouse warehouse;

   17

   18     [SetupResources]

   19     public void BeforeSpecificationExecute()

   20     {

   21         mockery = new MockRepository();

   22

   23         // setup the warehouse mock

   24         warehouse = mockery.CreateMock<IWarehouse>();

   25     }

   26

   27     [DestroyResources]

   28     public void AfterSpecificationExecuted()

   29     {

   30         mockery.VerifyAll();

   31     }

   32

   33     [Specification(Description=“Should not be able to fulfill order.”)]

   34     public void ShouldNotBeAbleToFulfillOrder()

   35     {

   36         string product = “Harry Potter and the Deathly Hollows”;

   37

   38         Order order = new Order(product, 50);

   39

   40         mockery.Record();

   41

   42         Expect.Call(warehouse.GetInventory(product)).Return(10);

   43

   44         mockery.ReplayAll();

   45

   46         order.Fill(warehouse);

   47

   48         Specify.That(order.IsFilled).Must.Equals(false);

   49     }

   50     [Specification(Description = “Should be able to fulfill order successful.”)]

   51     public void ShouldBeAbleToFulfillOrder()

   52     {

   53         string product = “Harry Potter and the Order of the Phoenix”;

   54

   55         Order order = new Order(product, 50);

   56

   57         mockery.Record();

   58

   59         Expect.Call(warehouse.GetInventory(product)).Return(61);

   60

   61         mockery.ReplayAll();

   62

   63         order.Fill(warehouse);

   64

   65         Specify.That(order.IsFilled).Must.Equals(false);

   66     }

   67 }

As you can see from reading the code snippet above, by using aliasing we are able to change the language we use. The cool thing about aliasing the NUnit attributes, is that your current build script or the tools you use to run your tests would still work effortlessly. But, now we are reading and thinking in terms of specifications and not tests. Cool Hey!

If you are wondering how I’m able to write Specify.That then you should check out NSpecify.

Technorati Tags: ,

Powered by ScribeFire.

Advertisements

Posted in BDD, Development, OO, TDD | 1 Comment »