Starting with BDD vs. starting with TDD
Yesterday I did a presentation on TDD/BDD at the Tamp Code Camp. I have done several TDD presentations in the past but this was the first time I also showed the attendees BDD at the same time. In actuality I didn’t even show them a traditional TDD test. Not to my surprise, newcomers seem to grasp BDD much quicker and easier than from a TDD perspective. I did touch on that some tests would still be driven from a technical aspect, but from a business requirements they should try to use BDD. Another thing I very briefly touched on was Mocks/Stubs. I try not to go too in depth as you can discuss mocks and stubs for an hour by themselves and isn’t worth it to dive into when all you have is an hour.
The best description I came up with for what is “BDD”, it’s nothing more than two things:
- A language shift in traditional TDD
- Driving your tests from a domain/user story perspective rather than technical perspective
[TestFixture]
public class addressbook_tests
{
[SetUp]
public void SetUp()
{
// setup code for test
}
[Test]
public void can_add_person_to_addressbook()
{
// test assertions
}
}</p>
As you can see. We have TestFixture/Test attributes. This is pretty straightforward and if you’ve been doing TDD you know how it works. Now let’s look at the same test using SpecUnit and with BDD language adjustments:
[Concern("Address Book"), TestFixture]
public class when_adding_a_person_to_an_addressbook : ContextSpecification
{
[Context]
protected override void Context()
{
base.Context();
// setup code for test
}
[Observation, Test]
public void addressbook_contains_person()
{
// test assertions
}
}</p>
- I have both Concern/TestFixture and Observation/Test attributes on the class/method. This reason I am doing this is because I am using Resharper. At the moment, resharper doesn’t recognize that Concern/Observation derive from TestFixture/Test and thus needs to be added so the Resharper test runner recognizes the tests. I have filed a bug with JetBrains and this will be fixed on the next release. It also helps to show what was a testfixture and test in the first example
- Instead of [SetUp] attribute you now have the [Context] attribute.
- There are other methods you can override from ContextSpecification like “Context_BeforeAllSpecs”, “Context_AfterAllSpecs” and so on.
- SpecUnit has a number of extremely useful extension methods that make for a much more readable assertions like: somevalue.ShouldEqual(“whatever”).
In BDD one of the biggest shifts is that your testfixture classes are now grouped together into “Concerns” and your classes are broken out into Contexts. So in the TDD example our individual tests defined the context, now we pull that context up to the class level and the tests then become the acceptance criteria for the context.
BDD has a much better alignment with business concerns and allows us to create tests that are parallel with User Stories/Acceptance criteria. This allows us to write software that is directly inline with what our stakeholders want rather than writing code that may or may not be necessary.
Moving on, lets look at another important part of BDD which has to do with reusing contexts in your tests. Ok, so lets say we are creating an addressbook in our “when_adding_a_person_to_an_addressbook” like so:
[Concern("Address Book"), TestFixture]
public class when_adding_a_person_to_an_addressbook : ContextSpecification
{
private AddressBook addressBook;
[Context]
protected override void Context()
{
base.Context();
addressBook = new AddressBook();
}
}</p>
public class behaves_like_addressbook : ContextSpecification
{
protected AddressBook addressBook;
protected override void Context()
{
base.Context();
addressBook = new AddressBook();
}
}</p>
Now both of the context test classes can derive from this class like so:
[Concern("Address Book"), TestFixture]
public class when_adding_a_person_to_an_addressbook : behaves_like_addressbook
[Concern("Address Book"), TestFixture]
public class when_searching_for_a_person_in_an_addressbook : behaves_like_addressbook</p>
So now any setup of the context that our classes share can be placed in the behaves_like_addressbook “Context Base class”. This is a part of bdd that comes from rspec. The ruby guys reuse their contexts in exactly this way. Then if you have additional context base classes along the way if you have two or more contexts that share behavior/setup. For instance. lets say we had a shared context further down we can set it up like this:
public class behaves_like_address_book_with_some_other_context : behaves_like_addressbook
{
protected override void Context()
{
base.Context();
// modify our context that was
// created in behaves_like_addressbook
}
}</p>
This really helps to promote reuse among the context setups in your tests. Also take a look at the SpecUnit.report.exe in the specunit project. It allows you to generate an html document from the name of your tests to hand to stakeholders. Very useful form of documentation.
Thats it for an introduction to bdd and to get the gist of it. Now heres a list of resources to get you started not only for the people that were in my presentation yesterday but also for any newcomers to BDD.
SpecUnit : BDD testing tool that was described in this post
schambers googlecode : My google code repository with my resharper templates and AddresBook sample for BDD
AutoHotKey : install this and execute the “TestNamingMode.ahk” from my google code repository, then you do crtl+shift+u to turn on test naming mode where spaces are turned into underscores for you. Thanks to jpboodhoo for this!
Jean-Paul Boodhoo’s Blog : this guy is a BDD master. He has excellent posts on BDD and if your not already, you should definately read his blog.
JetBrains ReSharper : alot of the people in my presentation were blown away when I showed them what resharper was capable of. For anyone that is interested you can obtain a 30-day trial
Any feedback would be greatly appreciated! till next time