30 plus bad

Behaviour-Driven Development has been percolating around in the collective consciousnesses of some of the communities I'm involved in. It's basically a methodology that has grown out of some of the weaknesses people have observed in test-driven development. Here's the thing: TDD is about design. Forcing yourself to think about tests before the code is actually written helps you think about design in new ways. Beginners to TDD often think it's all about the tests instead.

The main issue that BDD tackles is one of terminology—when you are constantly referring to tests in TDD, it's easy to forget that what you really care about is behaviour. It's not really about tests, (in fact, Dave Astels's book on TDD begins with the sentence, "This is not a book about testing.") those just happen to be the most obvious way to get check behaviour. So BDD tries to come in with a new vocabulary focusing on contexts and specifications and the word "should" that starts you off thinking in the right direction.

The common criticism here is that it's "just terminology". It's not really that revolutionary, it's just a new set of names. Now to be honest, I agree with that except for the word just. When people talk about coding styles and things to always be mindful of, one of the things that repeatedly comes up is how important good names are. Not to get all Sapir-Whorf on you, but the words you use really affect the way you think in an inescapable way. In fact, there's an excellent essay on Confucianism and Technical standards which states:

In a famous passage, Analects 13.3, Confucius was asked by a disciple what his first order of business would be if he were to govern a state. He replied, 正名, meaning roughly [...] "rectify the names." His disciple was somewhat incredulous and asked, "Would you be as impractical as that?" Confucius strongly rebuked his disciple and explained that proper nomenclature is the basis of language and that language is central to taking care of things.

In the words of the Master:

If language is not correct, then what is said is not what is meant; if what is said is not what is meant, then what must be done remains undone; if this remains undone, morals and art will deteriorate; if justice goes astray, the people will stand about in helpless confusion. Hence there must be no arbitrariness in what is said. This matters above everything.

All that to say: yes, BDD is (mostly) new words. But that's a big deal.

Oh yes; the point... I had one about here somewhere. Right—behave.el, my latest hackery:

(context "A list with three items"
       (tag list example)
       (lexical-let ((list (list "a" "b" "c")))

         (specify "should contain the first item"
                  (expect (first list) equal "a"))

         (specify "should push new values onto the front"
                  (push "d" list)
                  (expect (first list) equal "d"))

         (specify "should NOT remove the top item when reading the car"
                  (expect (first list) equal "d")
                  (expect (first list) equal "d"))

         (specify "should return the top item when popped"
                  (expect (pop list) equal "d"))

         (specify "should remove the top item when popped" 
                  (expect (pop list) equal "a")
                  (expect (pop list) equal "b"))))

It's BDD. In Emacs Lisp. (And it's only 89 lines of code.</brag>)

The most obvious difference it has from other libraries like RSpec (well, apart from Lisp) is that behave.el meant to run in an interactive environment rather than from the command line. You could certainly script it, but the tagging functionality is designed with interactivity in mind. The other thing is that you can't structure things in terms of "X should PREDICATE Y" since Lisp requires that the function go first. I suppose technically you could write a macro that would mangle things to the point where that would be feasible, but it definitely goes against the grain of Lisp and would require a lot of context switching. behave.el instead uses the expect macro to state expectations which the code should fulfill.

Being a first release, it's missing a few things. For starters, you can only expect either that a form is non-nil or that it is equal something. More flexibility in the expect macro is certainly to be desired. The other big thing is that each specify form does not start with a fresh binding of variables. (The setup methods in both Ruby's Test::Unit and rSpec both provide this, and it often proves to be handy.) I've been battling the CL-emulation libraries in elisp and so far losing, but I'm sure I can provide such a thing in a future release.

behave.el supercedes ElUnit, my previous unit-testing framework for Emacs Lisp.

Anyway, real point here is that now that I've got a BDD framework in Emacs Lisp, I can port it to Common Lisp and then use it to hack on Darjeeling. Woo hoo!

Grab it from my repository. There's also a Trac page.

« older | 2007-10-13T07:00:01Z | newer »