(Ab)using BDD For Fun And Profit

I’ve recently been let loose within the remit of trying to get some testing work organised. This has mainly led me towards User Stories and Planning Poker, with forays into TDD and BDD, specifically Speclj and Cucumber (well, cuke4php).

My Clojure work is non-existent, but I did manage to get it set up, very simply. I’m using Cuke at work, unfortunately mainly as a bootstrapper for integration testing.

One of the applications I work with is really a suite of four systems linked together by ActiveMQ. In order to test that a change on system A propogates through B and finally has the correct effect on C or D is a bit of a minefield if it’s being done manually - too many steps to perform (read: forget), and iterative changes are massively time consuming.

This is a prime suspect for BDD, I thought - I know what the process is (i.e. the success case), so I wrote that down. Separated it into five or six steps, each with sub-steps, just in a comment block.

I could then write these into Cucumber Scenarios, spotting where steps could be repeated. Then Cuke generated the stubs for these methods, and I coded away. A quick autoloader for classes I wanted to include (like AMQ connectors and cache interfaces), and some drop-in mocks for a static debug class that couldn’t be mocked in a nice way, and I was away.

I then (and here’s where it really descends into abuse) made it more generic by allowing arguments to be passed in on the scenarios. For example :

Given I have connected to queue:local.queue

This would be attached to a function like this :

 * Given I /^have connected to queue:(.*)$/
public function stepIHaveConnectedToQueue($name) {
    $q = new activemq($name);

You get the idea - with this type of extension I’m really using Cuke as a DSL for event scripting rather than testing. I only just thought of it as a DSL - this makes me worry about it less, to be honest.

Icing on the cake : systems C and D are pretty much the same, so I dumped the step_provider into an SVN external for inclusion in both, and then went though the motions of making it work on both simultaneously. This led to other hacks, like passing variables in to PHP through the $_SERVER array - As Cuke4php uses a client / server protocol to run, then $argv isn’t available to your features. In fact you get a Ruby error if you try to provide any standard arguments.

SYSTEM_TYPE=SYSTEM_C cuke4php features/integration.feature

You can then get SYSTEM_TYPE out of $_SERVER as normal.

One issue I have, and I’m not sure if it’s a problem or not, is that I can’t find a way to pass data through Scenarios. $this->aGlobals is cleared out every time a new Scenario is started. This is probably fine, as Scenarios are independant bits of functionality - if one fails then the others will be tried, so if there’s mutually required data between them then they are really only one scenario.

I am probably going to get lambasted by people for doing it this way - you are right, I am wrong. But I have a lot of legacy systems without unit tests and I need to check for regressions on a regular basis.

Abusing BDD in this way seems to be the quickest way to get it done.


11 September 2012