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:
- 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.
- 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.
- 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.
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:
- Should retrieve all completed orders for a given customer: PASSED
- Should retrieve order details for a given order id: PASSED
- Should create a new order for a given customer: PASSED
When a user has orders and views order history:
- OrderHistoryPresenter should request completed orders for user from OrderService: PASSED
- OrderService should retrieve completed orders for user from OrderRepository and map to DTO: PASSED
- OrderRepository should retrieve completed orders for user from DB: PASSED
- OrderHistoryPresenter should tell view to display completed orders: PASSED
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!