Big picture thoughts on software and other topics

November 5, 2007

Further Thoughts on BDD in C#

by Brian Donahue

So, now that I'm pretty well convinced that Behavior Driven Development is a logical and necessary evolution for (my) Test Driven Development, I've been thinking about ways I can better execute BDD with C# and .NET.  I am doing so with very limited knowledge of existing frameworks like NBehaveBroken Link: http://nbehave.org/, NSpec, NSpecify, and RSpec Broken Link: http://rspec.rubyforge.org/- but this is somewhat intentional.  I started thinking about how I would most like to work with BDD in my apps, and wanted to think it through before looking too hard at how I could work with existing frameworks. 

I am starting with the following understanding.  When doing BDD, you start with user stories, and associated acceptance criteria.   Programmers continue to work with customers to understand these and translate them into contexts and related tests and assertions.  In my previous post on BDD, I wrote about my initial attempt to write contexts as NUnit Test Fixtures with descriptive names such as When_a_user_has_orders_and_views_order_history.  The tests would follow a similar convention, e.g. Should_retrieve_all_orders_for_user_from_order_service(). Using underscores in a naming convention like that not only helps the names to read more like English, but can be used with a simple text parser to generate human-readable reports by swapping spaces for underscores.  This is especially useful when your customers are humans.

Separating contexts into separate test fixtures is very helpful for getting started with BDD, as it keeps you focused on driving out the functionality for that specific user story - in fact, a specific context within a specific story.  But as you go along, you end up with a whole heap of really ugly looking class names.  This bothers me for several reasons:

  1. ReSharper class/type navigation (Ctrl-N) becomes next to useless in your test library.  This may not bother you much if you haven't drunk the ReSharper kool-aid but I have and now can not live without this convenience.
  2. Finding tests that test specific areas of code becomes extremely difficult.  Code coverage tools like NCover/NCover Explorer help here, but if I want to check out the tests for a specific object or method, they are now scattered across multiple contexts/fixtures.
  3. As I mentioned in my prior post, you end up with some pretty redundant sounding contexts when testing different layers of your app, such as a When_service_retrieves_all_orders_for_user fixture and  a Should_retrieve_all_orders_for_user_from_order_repository() test method.  Look familiar (look back a couple paragraphs)?  Try sorting through a bunch of classes named thusly.  Also, there is nothing that explicitly ties these contexts together in any way, so it's hard to follow the flow of tests for a particular user story. 
Christian made a comment about just using these test names only for presenter tests, and then sticking with the more traditional [ClassName]Test naming convention for the other fixtures through the rest of the stack, while continuing the BDD style names for the actual Test Methods.  I had thought a little about this, as the presenter/view layer is closest to the user, and therefore typically the first step of the user story, so it lends itself to context-based naming.  There are a couple problems I have with this approach.  First, the presenter isn't always the beginning of a story, so that could lead to confusion.  Second, context is now lost for all other tests in the application.  In other words, you can't trace the tests easily for a single story or context.

What would be nice would be to keep the naming standards as [ClassName]Test with descriptive BDD-style test names of "ShouldDoWhatever" or "Should_do_whatever" but be able to relate tests to one or more contexts derived from user stories.  The result would be that you could generate a report for a specific Fixture/Class as well as for a specific context.  I believe that RSpec and NBehave give you this to a certain degree, but I'm not sure they would do exactly what I am thinking/hoping. (if I missed something, please enlighten me via a comment!)

In other words, I would be able to see two types of reports, as needed.  One would be the standard Fixture/Tests report:

OrderService:
And the other would be a context-based report:

When a user has orders and views order history:
I am not sure the latter is (cleanly) possible.  The only idea I've come up with is using Attributes above test methods to assign a context.  But this would lead to arbitrary strings (which seems to be standard practice in RSpec and NBehave) or trying to strongly type contexts, which is a bit goofy, and extra overhead.  Add in the concept of ordered tests as I have them displayed above, and that is more metadata overhead.  But I do think if the latter report could be achieved, it would be a great benefit to customers as well as developers. 

There was recent talk on the altnetconf mailing listBroken Link: http://tech.groups.yahoo.com/group/altnetconf regarding Resharper or TestDriven.NET features that would allow you to navigate from methods to their accompanying tests, and vice versa.  Along that same line of thinking, perhaps it would be possible to assign a context only to the first test in a path, and then following the method calls along through the application, you could display results for all the tests of all the methods that end up being called in the course of testing that context. 

All this stuff is way over my head, so can somebody else look into it!?? :-)  It is also likely that I'm not the first person to have thought of this, so if you know of anything out there, including the tools mentioned above, that do something along these lines, please share. 

If you have other/better ideas on how to achieve some of these things, please share them, too!