Submit Your Article
Home Articles News Tutorials Videos Add An Article
Topics: Design Photoshop Programming PHP CSS Java Database Web Development Javascript Ajax
– Close + Open

Find Out More About DevWebPro!

Sign up for the newsletter


» Terms & Conditions

Welcome to the New DevWebPro!

DevWebPro Includes:
  Hundreds Of Tutorials   Developer News
  Unique Gadget Videos   Tons of Topics to Discuss
  Expert Advice   We Will Publish Your Articles

Creating Behavior-Driven Actions

By: Sean Corfield
Wednesday, January 14th, 2009
Text: Decrease Font Size Increase Font Size | Print Print Article | Share: Delicious Digg StumbleUpon Post to Twitter Post to Facebook

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

Topics: ,

About the Author:
Sean is currently Chief Technology Officer for Railo Technologies US. He has worked in IT for over twenty five years, starting out writing database systems and compilers then moving into mobile telecoms and finally into web development in 1997. Along the way, he worked on the ISO and ANSI C++ Standards committees for eight years and is a staunch advocate of software standards and best practice. Sean has championed and contributed to a number of CFML frameworks and was lead developer on Fusebox for two years.

Leave a Comment

DevWebPro is an iEntry Network ® publication - © 1998-2010 All Rights Reserved