Viewing By Entry / Main
January 2, 2009
As folks know, I'm a big advocate of automated testing in general and unit testing in particular. I've gradually become a big fan of Test-Driven Development (TDD) where you write tests first and then write the code to satisfy the tests. I'm pleased to see unit testing well enough established in CFML development now that we have several unit testing frameworks (my current favorite being MXUnit, which I think has become the de facto standard choice for most CFers who are doing unit testing).

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 a.shouldBeAnInstanceOf("my.Object") />
<cfset b.shouldEqual("expected") />
The second feature is an application of cfimport that I've always liked but never seen a really good use of before: prefix="". This allows you to write simple tag-based code without the distracting library identifier, e.g.,
<cfimport taglib="/cfSpec" prefix="" />

<describe hint="Container">
<before>
<cfset list = $( createObject("component","util.List") ) />
</before>
<it should="be empty">
<cfset list.shouldBeEmpty() />
</it>
</describe>
In this specification, the describe, before and it tags are part of cfSpec. Using the empty taglib prefix allows the specification to be very readable.

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:

<cfset list.isEmpty().shouldBeTrue() />
Calling isEmpty() on the Expectations object in turn calls isEmpty() on the underlying object and returns an Expectations object based on the result of isEmpty() - which is boolean and should be true or false.

Comments

super radd!

been looking forward for someone to have the time to write a BDD DSL for CFML!


The bootstrap version of cfSpec is now available on RIAForge. http://cfspec.riaforge.org/


Post Your Comments
Name:
Email Address:
Comments
*** Please note that all comments require moderation so it may be some time before your comment posts to this blog! ***
Remember My Information:
 



Hosting provided by