Test-driven development has evolved significantly over the last five years, and it seems ColdFusion hasn’t caught up. Automated testing has remained a painful process in ColdFusion. But it doesn’t need to stay that way—that’s why we’ve started working on cfSpec, an open-source project to support behavior-driven development in ColdFusion.

Behaviour-Driven Development

Like several other recent movements in software development, behaviour-driven development (BDD) is about clearly communicating the intention behind code. In practice, it is not very useful to think in terms of tests at all, but rather in terms of behaviours. A behaviour communicates intent, while a test simply asserts something. A behaviour is concerned with what the code should do, whereas traditional test-driven development often leaves us talking about the nouns in the code and using method names like testLineItem which don’t actually say anything about what the code being tested should do. For a more thorough introduction to BDD, read Dan North’s introduction.

Introducing cfSpec

In order to support this shift toward clarity of intent, we need new tools that automatically reinforce the new paradigm. These tools are already being used in several other programming languages, so we thought it was high time for such a tool in ColdFusion. cfSpec is being modeled after rSpec by David Chelimsky. It has begun as a basic unit-testing spec framework, and will eventually include stubbing/mocking and a full story framework. You can follow our progress at http://github.com/adelphus/cfspec/, or even pitch-in if you are familiar with these tools and concepts.

What Does It Look Like?

Full documentation will come as we approach our first stable release. In the meantime, here’s a very brief example of what a spec looks like in ColdFusion:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<cfimport taglib="/cfspec" prefix="">

<describe hint="User">
 
  <before>
    <cfset user = $(createObject("component", "User"))>
  </before>

  <it should="be in any roles assigned to it">
    <cfset user.assignRole("assigned role")>
    <cfset user.shouldBeInRole("assigned role")>
  </it>

  <it should="not be in any roles not assigned to it">
    <cfset user.shouldNotBeInRole("unassigned role")>
  </it>

</describe>

And here is an unrelated example of what the current output looks like:

9 Responses to “cfSpec: Behaviour-Driven Development for ColdFusion”

  • So awesome to see cfSpec passing its own cfSpec tests!
  • John Farrar
    John Farrar
    OK, so besides testing... er, uhm, what does it do for building a web site that 'non-behavior' based CF code could not do? I see a geeky (and yes I like geeky also) way to code, but other than testing my project manager side is saying why?
  • @John, have you read Dan North's article? He explains why this approach (BDD) is an advance over (and is complementary to) TDD. TDD tends to force bottom-up testing and development whereas BDD supports more of a top-down approach since you're writing tests in the domain language of the problem space rather than the implementation space. It's why, for example, TDD advocates have been promoting verbose naming conventions for test methods - so that tests are closer to the domain language than the implementation language - but it doesn't go far enough.
  • @John, the case for BDD is subtle. You must keep in mind that it is an evolution of TDD, not an adversary. Personally, I've always had trouble doing TDD for reason's similar to the one's enumerated by Dan North. However, when I started using rSpec for my Ruby development, I found the proof in the pudding -- I was writing the specs first as an integral part of my thinking process, rather than feeling that I was artificially tacking some tests on. It changed the way I thought about my approach to development. It focused me and improved me as a developer. Furthermore, in BDD there is an implicit reminder to use intent-revealing names for methods, and to code in a human readable way. The significance from a project management standpoint becomes clear when you consider that most development time is spent on maintenance of an existing code base. This means that code which you can read and understand lowers time and cost of maintenance significantly. The focusing effect mentioned above also tends to improve code quality and overall design architecture, while steering developers away from implementing things which are insignificant to the desired behaviour of the system. These things save money and yield better software. And unit-level specs are just the beginning... more to come!
  • @sean "...but it doesn't go far enough." could you elaborate on that comment. I will not profess to be a master of BDD or TDD but I feel that using a unit testing framework be it MXUnit or TestNG I can write suites that allow me to attack a problem from with behavioral mindset.
  • srelliott
    srelliott

    Please test the behavior of the link to Dan North’s Intro to BDD ~ thanks!

  • srelliott, the link is fine. It appears that Dan North’s site is having trouble since all pages except the homepage are giving that error. Here’s a link to Google’s cache of the article. which may work for a while.

  • Ron,

    I am very interested by cfSpec and BDD. I have struggled in the past with TDD and I think you have expained some of the difficulty. I have been deleyed a bit by Dan North’ site being down and now it is back up I have time to read it.

    I have not has a chance to use cfSpec yet and maybe I missed somthing but in your examples you are using shouldNotBeInRole() and looks to me like there is a ShouldNotBe as we as a ShouldBe Matcher. Is there always a shouldNot for every matcher?

  • Kevin,

    You’ve made an excellent observation. Yes, all of the cfSpec matchers support both should and shouldNot variants. Although, in some cases, it’s not advisable to use the negative because it’s confusing (e.g., shouldNotHaveAtLeast(5).children() makes much more sense rendered as shouldHaveAtMost(4).children().)

Sorry, comments are closed for this article.