<< Converting an OS X Bootcamp Partition to a VMWare Virtual Machine | Home | First Philly ALT.NET Meeting This Wednesday >>

Further Thoughts on BDD in C#

posted @ Monday, November 05, 2007 11:31 AM

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 NBehave, NSpec, NSpecify, and RSpec - 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:
  • 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
And the other would be a context-based report:

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
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 list 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!

Comments

  1. Scott Bellware

    Posted on: 11/8/2007 2:18 AM

    # re: Further Thoughts on BDD in C#

    > 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

    That's not necessary. Write specs and context from the perspective of the experience of the software. Even models are experienced, and we can write about them from that perspective.

    It's really rare that we can't come up with a good context/specification for any part of the implementation. When I write about a service class or a model object, I write about the experience of it rather than writing about itself.

    An important part of the exercise is to keep your mind out of the technological gutter. For example: a method doesn't throw an exception - it's simply an experience that *isn't allowed*.

    > In other words, you can't trace the
    > tests easily for a single story or
    > context

    I never, ever, ever worry about tracing specifications back to stories. The stories are only there to get me some understanding of the needs of the user, the software experience, and the initial acceptance criteria.

    Once you have the initial acceptance criteria, you can write specifications. And those specifications lead to questions which lead to more, finer acceptance criteria.

    When the acceptance criteria is satisfied, you have working software. once you have working software, the user doesn't give a damn about user stories - he wants to talk about the way the software works, or doesn't work.

    Stories are just stem cells for producing acceptance criteria that grows into software through TDD.

    Specifications aren't there to help you trace your steps back to the protoplasm that the system starts from, they're there to document and verify the software which is ultimately the whole point of the exercise. We're not paid to build stories - the stories are just the scaffolding.

    Keep the specifications and keep the software. Everything else is just temporary bracing to keep the different perspectives of some feature from falling apart while they're being glued together.

    > 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

    RSpec allows you to stipulate both the code artifact under test as well as the description of the context:

    describe PersonController, "when saving a new person"

    The code code artifact (PersonController in the above example) is optional.

    I do this in .NET with some assembly metadata in order to get the richness of the documentation that RSpec delivers out of the box.

    I've got an update to my utilities classes for BDD with NUnit on Google Code that I plan to get out soon that will expand upon the spec reporting already available, including the ability to capture the code artifact under test.

    > I would be able to see two types of
    > reports, as needed. One would be
    > the standard Fixture/Tests report.
    > And the other would be a
    > context-based report

    You would, but are you speaking about a theoretical need, or a need that you presently have based on having worked with BDD-style specification and documentation?

    I think this might be a need that stems from force of habit. I'm not saying that you might still not want this, but you should let BDD specification become as second nature as developer testing is and then revisit this issue.

    > But this would lead to arbitrary
    > strings

    [Concern(typeof(PersonController))]

    > But I do think if the latter report
    > could be achieved

    Indeed... been using for almost a year now... :)

    > All this stuff is way over my head,
    > so can somebody else look into it

    Keep your eyes on NUnit Spec on Google Code. When I get around to checking in the experimental stuff sitting on my hard drive, you'll likely see all the stuff you're looking for... or at least enough to provide feedback on.

  2. Brian Donahue

    Posted on: 11/8/2007 9:41 AM

    # re: Further Thoughts on BDD in C#

    @Scott - Awesome, I wasn't aware that you were working on that stuff. Looking forward to trying it out.

    I've also heard your arguments about not keeping stories around after they've been implemented - and I don'tdisagree. I should have stuck with the term "context." I was thinking that for a specific context "when a user has completed orders and views her order history," it would be nice to be able to get a report of all the tests through the application that must pass to have that particular interaction be complete. Maybe I am missing something about the way you would approach this (the "story" being "as a developer, I want to show my customer that all my tests pass for a particular context, so that she can pat me on the back and let me go home to see my family."

    With RSpec how is this achieved? Or, could it be that you just show them integration tests, meaning you run the highest level test (the presenter or controller level) and have it actually do the work (no mocks in this test) and show them that? I would think both interaction and integration test results would be useful, but maybe interaction tests are more useful to the developer than the customer?

  3. Scott Bellware

    Posted on: 11/8/2007 4:04 PM

    # re: Further Thoughts on BDD in C#

    > I want to show my customer
    > that all my tests pass for
    > a particular context, so
    > that she can pat me on the
    > back and let me go home to
    > see my family

    Mommy doesn't care that you can do it with no hands. She's just giving you attention because she feels that you need it :)

    She really wants you to just give her some working software in manageable, bite-sized increments, and she wants to have confidence in you that you've done due diligence to make sure that it's well-designed and well-tested.

    Deliver business value. Software enables business value. Tests and specifications enable that software to be built. You don't deliver tests, so stop looking for accolades for simply having done your job. It's unattractive, and it puts a strain on your customer's confidence in your self-confidence.

    If you need to talk over your understanding of the requirements as you've implemented them, and if the customer is engaged at that level, then grab a copy of the spec report and go over it with your customer over a cup of coffee in the break room.

    There are domains where customer-oriented acceptance testing tools are valuable and applicable, but they are fewer than we tend to believe.

    Communicate over software whenever possible. Communicate over supporting and ancillary artifacts when necessary.

  4. Brian Donahue

    Posted on: 11/8/2007 5:35 PM

    # re: Further Thoughts on BDD in C#

    >It's unattractive, and it puts a
    >strain on your customer's confidence
    >in your self-confidence.

    Ouch! I understand your point, though. I guess the disconnect for me is, one of the cool things I saw about RSpec was that report generation that could be read by business users. Understanding that they don't want to read the results of every test for every piece of the app, what reports DO you find useful to show them? The controller tests alone? Integration tests?

    I'm sure the answer is "it depends," and "sometimes they don't need to see anything but the software." But I know you mentioned sharing these reports with customers in your BDD session, and I'd like to hear some good examples of where BDD artifacts (specs) were used to help communication with the customer.

    I am understanding, and appreciating the value of the conversation to get you to a spec that you then test... I just want to hear more about the use of those specs later when showing the customer what you've got to get feedback/approval/whatever it is that you want to get!

  5. Scott Bellware

    Posted on: 11/8/2007 8:41 PM

    # re: Further Thoughts on BDD in C#

    > one of the cool things I
    > saw about RSpec was that
    > report generation that
    > could be read by business
    > users

    The RSpec output is valuable for everyone on the team.

    It's not so much a 'report for business users' as it is a 'report about the application in the business language'.

    Depending on how comfortable the customer is with the tech stuff, they might be willing to read the report on their own. Once the app has more than a paltry codebase, the report can get pretty big and it'll be hard to navigate for a customer.

    The value of the report for me is in going over it **with** the customer in order to clarify what has been done. And this is really only an issue if expectations haven't been met.

    The primary use for the report for the most part is in serving the technologists to help them switch back and forth between thinking about the business and thinking about the technology implementation.

    The spec report is a perspective of the design. It's a 100-foot view through business-colored lenses. I use it to gain perspective, and from this perspective, I sometimes find design flaws that I wouldn't have seen from the implementation perspective.

    Using the spec report with the customer is valuable, but it's not the customer's primary attachment. Working, self-evident software is the customer's concern. If you show them that, and if you meet their expectations, then they won't need to dig into the spec report. Even if you don't meet their expectations, you can still rectify the situation without having them look at the spec report.

    In Austin, I said that I can use the spec report in a conversation with the customer along the lines of, "You asked me to do X. Here's what I understood X to mean. Is this correct?"

    The customer may not even have the report in-hand. I might just read off the specification bullet points out loud.

    Again the spec report isn't a primary interface point with the team. The software is. But, it's useful in some customer engagement scenarios. And, it's always useful for programmers to keep their minds on the business and on the experience of the app.

  6. Brian Donahue

    Posted on: 11/8/2007 9:39 PM

    # re: Further Thoughts on BDD in C#

    @Scott - Gotcha. I think I have a better understanding now. Thanks for all the feedback!

Your comment:



 (will not be displayed)


  Please add 8 and 6 and type the answer here: