Dave Laribee

Sponsors

The Lounge

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
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):

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:

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.


Posted 12-17-2007 5:38 PM by Dave Laribee

[Advertisement]

Comments

Adam Tybor wrote re: Approaching BDD
on 12-17-2007 6:26 PM

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.

Dave Laribee wrote re: Approaching BDD
on 12-17-2007 6:33 PM

> 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...

dan » Approaching BDD wrote dan &raquo; Approaching BDD
on 12-17-2007 7:16 PM

Pingback from  dan &raquo; Approaching BDD

Patricia wrote re: Approaching BDD
on 12-18-2007 12:23 AM

thanks for the information.

Joe Ocampo wrote re: Approaching BDD
on 12-18-2007 2:01 AM

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.

Kyle Baley wrote re: Approaching BDD
on 12-19-2007 7:09 AM

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.

Dave Laribee wrote re: Approaching BDD
on 12-19-2007 10:17 AM

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...

Jean-Paul S. Boodhoo wrote BDD Specification Base Class
on 12-19-2007 3:44 PM

With a newfound interest in leveraging the AutoMockingContainer (credit to James for convincing me of

Colin Jack wrote re: Approaching BDD
on 12-29-2007 2:52 PM

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 tech.groups.yahoo.com/.../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: tech.groups.yahoo.com/.../165

Colin Jack wrote re: Approaching BDD
on 12-30-2007 7:51 AM

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...

Community Blogs wrote BDD Style Specification Reporting via CC.NET
on 01-02-2008 11:16 AM

After reading posts by Jean-Paul Boodhoo and Dave Laribee regarding BDD style naming conventions for

DotNetKicks.com wrote Approaching BDD
on 01-02-2008 12:42 PM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Books + Head First C# + Lab 1 Solution « just in ram wrote Books + Head First C# + Lab 1 Solution &laquo; just in ram
on 01-03-2008 5:22 PM

Pingback from  Books + Head First C# + Lab 1 Solution &laquo; just in ram

mattcalla.com wrote BDD Style Naming Macro for Visual Studio
on 01-15-2008 3:43 AM

I've really jumped on board with BDD (Behavior Driven Development) in the past week. I've been reading about it for a while, but it wasn't until I started actually doing it on a side project of my own that I've really begun to realise how good it can

Matthew Podwysocki's Blog wrote Fluency in Fluent Interfaces
on 02-01-2008 5:50 PM

Scott Hanselman's recent post about the Daily Source Code 14 - Fluent Interface Edition got me to think

Alec Lazarescu's Blog wrote Testing Theories Part 3 - IoC Containers (Castle Windsor, Spring.NET), AutoMocking Containers
on 02-19-2008 12:15 AM

IoC can certainly be done manually without the help of a container, but there are advantages to using

Matthew Podwysocki's Blog wrote Coming to Terms with Behavior Driven Development
on 03-03-2008 6:29 PM

A while ago, I posted about Behavior Driven Development (BDD) while using the NBehave , and I think I

Dave Laribee wrote Early Tool Theory
on 04-03-2008 10:06 PM

I got into a series of interesting conversations with the usual suspects , Austin edition , about tools

Links Today (2008-04-04) wrote Links Today (2008-04-04)
on 04-04-2008 11:33 AM

Pingback from  Links Today (2008-04-04)

Elegant Code » Thanks to BDD wrote Elegant Code &raquo; Thanks to BDD
on 05-01-2008 2:49 PM

Pingback from  Elegant Code &raquo; Thanks to BDD

Bj??rn Rochel’s weblog » First steps with BDD wrote Bj??rn Rochel&#8217;s weblog &raquo; First steps with BDD
on 08-27-2008 7:35 AM

Pingback from  Bj??rn Rochel&#8217;s weblog &raquo; First steps with BDD

BDD in CSLA « maonet technotes wrote BDD in CSLA &laquo; maonet technotes
on 08-29-2008 6:19 PM

Pingback from  BDD in CSLA &laquo; maonet technotes

Tim Van Wassenhove » Archive » Experimenting with naming conventions for unit tests wrote Tim Van Wassenhove &raquo; Archive &raquo; Experimenting with naming conventions for unit tests
on 09-05-2008 9:28 AM

Pingback from  Tim Van Wassenhove  &raquo; Archive  &raquo; Experimenting with naming conventions for unit tests

[code] - mattcalla.com wrote BDD Style Naming Macro for Visual Studio
on 11-28-2008 12:57 AM

I've really jumped on board with BDD (Behaviour Driven Development) in the past week.

Add a Comment

(required)  
(optional)
(required)  
Remember Me?