BDD vs TDD

I wanted to put a simple test in place to document the behaviour of a value converter WPF application I am working on is using. First I did it the standard TDD way (sort of spiking multicultural support of MbUnit framework). The result worked great.

   1:    [Concern(typeof (CurrencyConverter))]
   2:    [TestFixture]
   3:    public class when_converting_with_CurrencyConverter
   4:    {
   5:      [Test]
   6:      [MultipleCulture("en-US,fr-CA")]
   7:      public void should_format_to_currency_using_current_culture_with_no_decimals()
   8:      {
   9:        var value = 2000d;
  10:        IValueConverter sut = new CurrencyConverter();
  11:        var result = sut.Convert(value, null, null, Thread.CurrentThread.CurrentCulture);
  12:   
  13:        result.ShouldBeEqualTo(value.ToString("C0"));
  14:      }
  15:    }

The MultiCultureAttribute was very handy and it did not report the single test as 2 tests in the headcount (having same thing done with RowTest would count test for two, or actually for each RowAttribute applied along with RowTestAttribute).

Now I wanted this to be expressed in a BDD style, since BDD makes more sense from both readability and maintainability perspectives. The code looked like:

   1:    [Concern(typeof (CurrencyConverter))]
   2:    [TestFixture]
   3:    public class when_converting_with_CurrencyConverter : SpecificationContext<IValueConverter>
   4:    {
   5:      private double value;
   6:      private object result;
   7:   
   8:      protected override IValueConverter EstablishContext()
   9:      {
  10:        value = 2000d;
  11:        return new CurrencyConverter();
  12:      }
  13:   
  14:      protected override void BecauseOf()
  15:      {
  16:        result = sut.Convert(value, null, null, Thread.CurrentThread.CurrentCulture);
  17:      }
  18:   
  19:      [Test]
  20:      [MultipleCulture("en-US,fr-CA")]
  21:      public void should_format_to_currency_using_current_culture_with_no_decimals()
  22:      {
  23:        result.ShouldBeEqualTo(value.ToString("C0"));
  24:      }
  25:    }

Unfortunately this failed. Reason - EstablishContext() and BecauseOf() are both executed upon SetUp of the TextFixture. Therefore the sut being created is there for both tests - with the first culture (en-US).

Listing of the SpecificationContext<T> base class:

   1:    [TestFixture]
   2:    public abstract class SpecificationContext<SystemUnderTestType>
   3:    {
   4:      protected SystemUnderTestType sut;
   5:   
   6:      [SetUp]
   7:      protected void Setup()
   8:      {
   9:        sut = EstablishContext();
  10:        BecauseOf();
  11:      }
  12:   
  13:      [TearDown]
  14:      protected virtual void Cleanup(){}
  15:   
  16:      protected abstract SystemUnderTestType EstablishContext();
  17:      protected abstract void BecauseOf();
  18:      protected TypeToStub Stub<TypeToStub>()
  19:      {
  20:        return MockRepository.GenerateStub<TypeToStub>();
  21:      }
  22:      protected TypeToMock Mock<TypeToMock>()
  23:      {
  24:        return MockRepository.GenerateMock<TypeToMock>();
  25:      }
  26:   
  27:    }

As you can see, the problem is that for both cultures the test is running with only once executed Setup, where the context is established and reason for test is created.

One way to solve it is to split the TestFixute into to. I am not likely to prefer this due to the fact that it defeats the purpose of testing - simple and quick. Another way, the one I will probably implement, is revert from BDD to classic TDD.

Although this is what I've decided for this particular test, this does have implications on other UI testing where multicultural support is important. In case any of you my dear readers has run into similar situation and managed to figure out a solution for BDD way, please share your experience.

No Comments