Approaching BDD

I’m preparing a chunk of code for open source release in January. Among many other things it has a persistence layer wrapper with a “provider” for NHibernate, yet another validation framework, and a few goodies for building smart clients. It’s not dissimilar to Ayende’s Rhino Commons in fit or purpose. Some parts would suit any application. Others are targeted at the “smart client” domain. For example I have a front controller for windows forms. Wacky.

This is the first of a series of code-focused posts where I’ll attempt to explain the motivations behind the major elements of the codebase and/or explain some steps in getting the codebase ready for public consumption.

—-

I’m plowing through a substantial chunk of the test code having decided to convert test fixtures over to the specification style Scott and JP have been advocating. Essentially the technique involves using multiple classes to describe the contexts (BDD-style) for testing a particular behavioral unit. Most often, these tend to be individual classes.

Here’s an example of part of a specification for a infrastructure class, TransactionElection, that supports our unit of work implementation (more on that later):


.csharpcode, .csharpcode pre
{
font-size: 8pt;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

using System;
using NUnit.Framework;
using Rhino.Mocks;
using XEVA.Framework.Model.UnitOfWorkImpl;
using XEVA.Framework.Specs;
using XEVA.Framework.Model;

namespace Specs_for_TransactionElection
{
[TestFixture]
public class When_an_election_is_started : Spec
{
private ITransaction _stubTransaction;
private TransactionElection _election;

protected override void Before_each_spec()
{
_stubTransaction = Stub<ITransaction>();
_election = new TransactionElection(_stubTransaction);
}

[Test]
public void The_result_should_be_in_progress()
{

Assert.AreEqual(_election.Result, TransactionElectionResult.InProgress);
}
}

[TestFixture]
public class When_votes_are_cast : Spec
{
private TransactionElection _election;
private ITransaction _transaction;

protected override void Before_each_spec()
{
_transaction = Mock<ITransaction>();
_election = new TransactionElection(_transaction);
}

[Test]
public void A_single_no_vote_should_rollback_the_transaction()
{

using (Record)
{
_transaction.Rollback();
}

using (Playback)
{
_election.CreateVote();
_election.VoteNo();
}
}

[Test]
public void A_no_vote_will_leave_the_election_with_a_finished_and_voted_no_status()
{
using (Record)
{
_transaction.Rollback();
}

using (Playback)
{
_election.CreateVote();
_election.VoteNo();
Assert.AreEqual(TransactionElectionResult.FinishedNo, _election.Result);
}
}

[Test]
public void Unanimous_yes_votes_will_commit_the_underlying_transaction()
{
using (Record)
{
_transaction.Commit();
}

using (Playback)
{
_election.CreateVote();
_election.CreateVote();
_election.VoteYes();

Assert.AreEqual(TransactionElectionResult.InProgress, _election.Result);

_election.VoteYes();
}
}

[Test]
public void A_yes_vote_will_leave_the_election_with_a_finished_and_voted_yes_status()
{
using (Record)
{
_transaction.Commit();
}

using (Playback)
{
_election.CreateVote();
_election.CreateVote();
_election.VoteYes();

Assert.AreEqual(TransactionElectionResult.InProgress, _election.Result);

_election.VoteYes();

Assert.AreEqual(TransactionElectionResult.FinishedYes, _election.Result);
}
}
}

There are a couple of things to look for in this sample (and, yes, you’ll be able to download it, use it, complain about it, etc. under the MIT license very soon). First, I use the namespace to describe the class that’s being specified. I’m a little bothered by this as I feel true BDD would ignore this fact. In a way, these specifications are very TDD-style as they all rally around a single class. To be honest, at this point I’m okay with this. It’s as if the TranactionElection class were the direct object in each sentence of specification.

To cut down on line noise I use a base class for my specifications (aka test fixtures). I could take it a bit further with AutoMockingContainer. That’s a good change for a rainy day, so, for now, I’m going with a low fidelity technique for making my specs a little bit cleaner. Here’s the Spec class:


.csharpcode, .csharpcode pre
{
font-size: 8pt;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

using System;
using NUnit.Framework;
using Rhino.Mocks;

namespace XEVA.Framework.Specs
{
[TestFixture]
public class Spec
{
private MockRepository _mocks;

[SetUp]
public void MainSetup()
{
_mocks = new MockRepository();
Before_each_spec();
}

[TearDown]
protected void MainTeardown()
{
After_each_spec();
}

public MockRepository Mocks
{
get { return _mocks; }
}

protected virtual void Before_each_spec() { }

protected virtual void After_each_spec() { }

protected IDisposable Record
{
get { return _mocks.Record(); }
}

protected IDisposable Playback
{
get { return _mocks.Playback(); }
}

protected TType Mock<TType>()
{
return _mocks.DynamicMock<TType>();
}

protected TType Partial<TType>()
where TType : class
{
return _mocks.PartialMock<TType>();
}

protected TType Stub<TType>()
{
return _mocks.Stub<TType>();
}

protected void Verify(object mock)
{
_mocks.Verify(mock);
}

protected void VerifyAll()
{
_mocks.VerifyAll();
}
}
}

The main reason I am appropriating the namespace is to receive a specification output that reads easily in tooling. It’s a bit easier than using an attribute on each class and you don’t really need the namespace for the specifications.

Here’s a screen shot from the ReSharper test runner:

resharper-specs

Sexy.

I could take my test runner (NUnit) output and easily format a report should that become desirable:

Specifications for TransactionElection

    When votes are cast,

        a single no vote should rollback the transaction.

        a no vote will leave the election with a finished and voted no status.

        unanimous yes votes will commit the underlying transaction.


    …

All things considered I’m not sure I’m 100% convinced. Let’s say ~90%. I know I like the output, but I think reverse engineering TDD-style tests to BDD-style tests have left my contexts (when) a little soft in the middle. I’m going to keep going through a few of the larger fixtures to see if any refactoring patterns or tips emerge and I’ll be sure to revisit these tests based on accumulated experience. I will say that I believe it’s ok to use technical language for technical/infrastructure classes as evidenced in the presented example.

I am trying to banish the term “test” from my vocabulary. At least as far as “unit tests” or “test-driven development” go. I really see developer testing (there we go again) as a process of leaving a breadcrumb trail of executable specifications. In a domain modeling scenario these tests may/should be business-readable. In the case of a TransactionElection class you’re really leaving multiple entry points for other developers to reenter code. This is key to enabling collective ownership.

Look for more posts on this subject (along with a code drop) soon.

This entry was posted in Agile, BDD, Featured, open source, TDD, xeva release series. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

8 Responses to Approaching BDD

  1. Colin Jack says:

    Woops, I deleted the second ALT.NET forum entry because I realized it wasn’t ALT.NET specific then remembered I had linked to it here…

  2. Colin Jack says:

    Interesting. As you say this shows tests for a piece of infrastructure code but I’ve struggled to work out how to use BDD when testing your domain model and I’d be very interested in your advice.

    I should say that I tend to find that state testing works well when driving domain model design. I have a few reasons for this, some of which I’ve listed here http://tech.groups.yahoo.com/group/altdotnet/message/202.

    My problem is then that BDD seems to really focus on interaction testing. I don’t do much interaction testing within the domain, if I do use a mocking framework its mainly to created stubs/fakes and I usually just use the real domain objects (from a builder or Object Mother). Since I don’t really do interaction testing at the domain level do you think I’d lose some of the benefits of BDD?

    I’ve also created an ALT.NET forum entries for this: http://tech.groups.yahoo.com/group/altdotnet/message/165

  3. Dave Laribee says:

    i thought he posted his macro.

    i just turn off intellisense and boxcut my names by hand. laziness or studliness? i’ll leave that determination to you. though i will say that the studly are often quite lazy…

  4. Kyle Baley says:

    Oh good! You’re looking into this, too. I’ve started…ummm…testing out this method of naming as well and it’ll be nice to have someone in the same boat. We can be learning buddies!

    I heard tell that JP has a macro for formatting test results like this into a report but I haven’t verified it yet.

  5. Joe Ocampo says:

    Awesome David!

    One thing I forgot to comment on was the use of Category Attribute in the test fixture name.

    [TestFixture, Category(“Specs_for_TransactionElection”)]

    I know you had mentioned that it is “…easier than using an attribute on each class and you don’t really need the namespace for the specifications.”

    I agree however some developers have a hard time with the namespace containment. One of my earlier post simply had the namespace but in practice that didn’t go over with the team very well in the beginning. So I included the Category attribute to help with the navigation. In the end several of the them have abandoned the use of the category as they rely on the namespace for grouping.

    Just giving people options if they have a rough time implementing this approach.

    ctrl-shift-n is their best friend.

  6. Patricia says:

    thanks for the information.

  7. Dave Laribee says:

    > I want some more guidance.

    I asked Joe and Scott for a peer review but got impatient. I’d like some more tips as I’m unset as of now. I’m not asserting a position of authority here, so I hope this will solicit some debate, tips, tricks, etc. In general, BDD on .NET (from my view) is new craft.

    > TD.NET.

    Yes TD.NET will run if your right click on the namespace “Specs_for_TransactionElection.” I picked the R# test runner because it’s so pretty. Day-to-day I use TD.NET…

  8. Adam Tybor says:

    Maybe a dumb question, but using a namespace I am assuming you can get TD.Net to run tests in the whole namespace? I have seen similar setups before but with nested classes and I could not get TD.Net to run all the fixtures inside the nested class.

    Please keep more BDD posts coming, I am intrigued and totally at loss at how to structure my tests in an elegant fashion. I watched the screencast at los-techies and then listened to Scott say that it was entirely wrong on the Alt.Net mail list. I want some more guidance.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>