Some thoughts on Cucumber and Behaviour Driven Development

UPDATE: A few years after writing this I concluded that things like Cucumber introduce unnecessary overhead (see here).

I've been experimenting with behaviour driven development (BDD) using Cucumber lately. The idea is that you write (formalised) specs which describe the behaviour of your system, and they can also be executed as tests. E.g. I have this in my tests:

Scenario: Transcriber tries to start a transcription session when there are no calls
Given I log in as a normal user
And there is no work waiting
When I follow "Start processing"
Then I should see "There is nothing to process"

Each line of text in the scenario has a matching test method. The way I have things set up, when this is executed as a test, it starts up the browser, performs the login, presses the button and then checks the content of the response. The user simulation is done using Capybara which in turn uses Selenium to drive Firefox. It's capable of executing JavaScript too.

You could write the same thing in Ruby, e.g. using RSpec (a test library), and with appropriate helper methods written, the same test would be something like:

it "should inform the user when there is no work available" do
  login()
  delete_waiting_work()
  click_link "Start processing"
  page.should have_content "There is no work available"
end

It looks quite similar for this example, however I find that using Cucumber (i.e. the original example) has advantages:

  • the main thing I think, is that it forces you to think at a high level, because you want to write steps as succinctly as possible, and you'll have to write a lot if you don't keep up the level of abstraction
  • it's easy to start writing tests and describing the behaviour of the system before starting the implementation, because it's decoupled from the code
  • it makes it easier to think in terms of user actions (e.g. I login, I click on a link, I see a table with these rows)
  • you get a readable spec, which is useful e.g. when exploring what somebody else's application
  • making the spec and the tests one and the same is the easiest way to have an up-to-date spec.
  • you can even expect non-technical people to be able to read it, which may be useful, e.g. I could email this test to my customer to confirm that it's the behaviour he wants, and he would understand what's happening.

I'm sure some of this could be achieved with RSpec or another test library but it would require more discipline. With Cucumber, you can't really slip into lower-level code in your test. And by the way, I still write some unit tests using RSpec, but they are limited to testing out particular functions.

The key thing, I think, is not so much the syntax but the fact that this approach results in tests which are focused on the behaviour of the system as seen by the user, at a higher level than classes or even individual components.