Getting into TDD is not easy, however, and I think there are a couple of conceptual problems that take a while to get your head around. One is just a simple case of "Where do I start?". Given a blank piece of paper, how do you just start writing tests that are an accurate representation of what the yet-to-be-written system is supposed to do?
We know how to design systems - we start out with use cases and scenarios (or, if you prefer the more traditional terminology, requirements) and we iteratively map those down into system components and interactions and then down into elements that can actually be implemented. This software design process should also help you recognize the next big problem with trying to adopt TDD: unit testing - and TDD in general - focuses on small, testable pieces of code, i.e., methods and classes.
A couple of years ago, Dan North introduced the concept of Behavior-Driven Development which was intended to help tackle the disconnect between the low-level focus of TDD and the higher-level focus of requirements. What he wanted to do was to find a way to specify higher-level behaviors in the system in a form that could still be executed as a set of tests.
Since then, a number of frameworks have appeared in a variety of languages to support Behavior-Driven Development (see the implementation section) including RSpec (for Ruby) and GSpec (Groovy), supplementing existing TDD frameworks and techniques. I'm very pleased to see that Ron Hopper has just announced cfSpec: Behavior-Driven Development for ColdFusion!
I downloaded a snapshot this morning and started writing behavioral tests pretty much immediately, despite the current lack of documentation (there is a nice directory full of sample tests). cfSpec makes use of two powerful features to allow a rich, descriptive approach to specifying the behavioral tests. The first is one of my favorite ColdFusion 8 features - onMissingMethod() - which is used to allow behavior specifications to be written in close to natural language:
<cfset b.shouldEqual("expected") />
<describe hint="Container">
<before>
<cfset list = $( createObject("component","util.List") ) />
</before>
<it should="be empty">
<cfset list.shouldBeEmpty() />
</it>
</describe>
The behavior under test - it should be empty - runs onMissingMethod() on the Expectations object (created by the call to the $() method) and, because it is "should BeEmpty", it checks the list is empty, by calling isEmpty() (because the value underlying the expectation is an object, not a simple value). Essentially, for objects, shouldBeXyz() maps to a call to isXyz() on the underlying object (and checks the result is true).
Another way to write the behavior under test would be:
been looking forward for someone to have the time to write a BDD DSL for CFML!


