DanNorth.net

June 17, 2007

Introducing rbehave

rbehave is a framework for defining and executing application requirements. Using the vocabulary of behaviour-driven development, you define a feature in terms of a Story with Scenarios that describe how the feature behaves. Using a minimum of syntax (a few “quotes” mostly), this becomes an executable and self-describing requirements document.

BDD has been around in the Ruby world for a while now, in the form of the excellent rspec framework, which describes the behaviour of objects at the code level. The rspec team has focused on creating a simple, elegant syntax and playing nicely with other frameworks, in particular Rails and the Mocha mocking library.

Inspired by this, I wanted to find a simple and elegant way in Ruby to describe behaviour at the application level. This is a different enough problem that I couldn’t just use rspec. You can skip ahead to the Ruby code if you already know about stories and scenarios. This preamble just sets the scene for the example.

The scenarios that describe a story are made up of “steps” of Givens, Events and Outcomes. These steps can be mixed and matched in different ways to provide different sequences of events. Here is an example:

Story: transfer to cash account As a savings account holder I want to transfer money from my savings account So that I can get cash easily from an ATM Scenario: savings account is in credit Given my savings account balance is \$100 And my cash account balance is \$10 When I transfer \$20 Then my savings account balance should be \$80 And my cash account balance should be \$30 Scenario: savings account is overdrawn Given my savings account balance is -\$20 And my cash account balance is \$10 When I transfer \$20 Then my savings account balance should be -\$20 And my cash account balance should be \$10

Here we have two givens: one about my savings account and the other about my cash account. We have a single event, namely transferring cash. We have two outcomes, again about the account balances.

This is typical of the scenarios in a story: they revolve around a single event (the feature itself) and prescribe different outcomes for different combinations of givens. Also, notice that the steps themselves are parameterized: the first time my savings account balance is $100, the second time it is -$20, so a story framework needs to accommodate this.

Getting it running

So then I converted the story into a rspec-like structure, preferring simple strings to method names, and do/end blocks rather than classes:

require ‘rubygems’ require ‘rbehave’

Story “transfer to cash account”,
%(As a savings account holder I want to transfer money from my savings account So that I can get cash easily from an ATM) do

Scenario “savings account is in credit” do Given “my savings account balance is”, 100 Given “my cash account balance is”, 10 When “I transfer”, 20 Then “my savings account balance should be”, 80 Then “my cash account balance should be”, 30 end Scenario “savings account is overdrawn” do Given “my savings account balance is”, -20 Given “my cash account balance is”, 10 When “I transfer”, 20 Then “my savings account balance should be”, -20 Then “my cash account balance should be”, 10 end end

Using rspec to drive the design, I wrote a little framework that would run these scenarios, each one in its own instance of an object (so they were independent), reusing the steps as needed.

So, this only left the problem of the steps themselves. They would have to be defined somewhere else (that I hadn’t figured out yet). Then I thought: each step’s implementation should be pretty trivial, so what would happen if I put the code for each step inline in the scenario? So I ended up with this:

require ‘rubygems’ require ‘rbehave’ require ‘spec’ # for “should” method

require ‘account’ # the actual application code

Story “transfer to cash account”,
%(As a savings account holder I want to transfer money from my savings account So that I can get cash easily from an ATM) do

Scenario “savings account is in credit” do Given “my savings account balance is”, 100 do |balance| @savings_account = Account.new(balance) end Given “my cash account balance is”, 10 do |balance| @cash_account = Account.new(balance) end When “I transfer”, 20 do |amount| @savings_account.transfer_to(@cash_account, amount) end Then “my savings account balance should be”, 80 do |expected_amount| @savings_account.balance.should expected_amount end Then "my cash account balance should be", 30 do |expected_amount| @cash_account.balance.should expected_amount end end Scenario “savings account is overdrawn” do Given “my savings account balance is”, -20 Given “my cash account balance is”, 10 When “I transfer”, 20 Then “my savings account balance should be”, -20 Then “my cash account balance should be”, 10 end end

For this example it turns out there are no new steps to define in the second scenario, which makes it very easy to read. In general I’m finding that most of the steps get defined in the first one or two scenarios.

Implementing the code

So I saved this to a file as transfer_funds.rb and ran it, and I got two failures:

Running 2 scenarios: FF

2 scenarios: 0 succeeded, 2 failed

FAILURES:
1) transfer to cash account (savings account is in credit) FAILED
NameError: uninitialized constant Account
...
2) transfer to cash account (savings account is overdrawn) FAILED
NameError: uninitialized constant Account
...

rbehave prints one character per scenario – a dot means the scenario passed, an F means it failed. At the end of the run it prints a list of the failing scenarios. So this tells me that firstly it runs (hooray!) and secondly both scenarios are failing because I’m missing an Account class. Well I don’t want a whole bunch of failing scenarios that only start to work one at a time as I implement them. That feels too much like broken windows – I’ll get too used to seeing failing scenarios and then I won’t react when workng scenarios start failing. So I introduced the idea of a “pending” scenario, by adding a pending() method:

Given “my savings account balance is”, 100 do |balance| pending “needs an Account” @savings_account = Account.new(bal) end

And I got this:

Running 2 scenarios: PP

2 scenarios: 0 succeeded, 0 failed, 2 pending

Pending:
1) transfer to cash account (savings account is in credit): needs an Account
2) transfer to cash account (savings account is overdrawn): needs an Account

The Ps represent pending scenarios, which means they aren’t working yet but they don’t count as a failure. Then I use rspec to implement an Account with a constructor that takes an initial balance, and give it a transfer_to method that moves money around. Then I remove the pending line:

Running 2 scenarios: .F

2 scenarios: 1 succeeded, 1 failed, 0 pending

FAILURES:
1) transfer to cash account (savings account is overdrawn) FAILED
Spec::Expectations::ExpectationNotMetError: expected -20, got -40 (using )
...
</code>

Excellent! I have my first working scenario. Now I just need to add behaviour to the Account class to not transfer money it doesn't have! But wait a minute, what about documentation? Well I added some listeners to the story runner, so when you run:

<code>transfer_funds.rb --dry-run --format simple</code>

you get:

<code lang="text">
Story: transfer to cash account
As a savings account holder I want to transfer money from my savings account So that I can get cash easily from an ATM

Scenario: savings account is in credit Given my savings account balance is 100 Given my cash account balance is 10 When I transfer 20 Then my savings account balance should be 80 Then my cash account balance should be 30

Scenario: savings account is overdrawn Given my savings account balance is -20 Given my cash account balance is 10 When I transfer 20 Then my savings account balance should be -20 Then my cash account balance should be 10
</code>

This is being generated from the same Ruby code that runs the scenarios themselves.

Next steps

You can gem install rbehave or "download the source":http://rubyforge.org/scm/?group_id=1475. There is a sample application (Conway’s Game of Life) in progress in the source code that shows you some of the other features rbehave supports.

rbehave was designed to play nice with other frameworks. In particular, the "world" that each scenario runs in is a module that can be mixed into any object, so you could easily use rbehave with a Rails IntegrationTest or incorporate it into your existing acceptance testing framework. It is also possible, and in fact encouraged, to use rspec in your Outcomes (balance.should 30).

If you’re interested in using or developing rbehave, please join the mailing lists and let me know how you get on. As a parting thought, rbehave is totally compatible with jruby, so you could start writing your Java acceptance criteria in Ruby and running them in rbehave.

A number of people helped me get rbehave off the ground. In particular I have to thank Niclas Nilsson for kick-starting the whole thing, David Chelimsky (rspec lead) for his sound advice and for adding describe/it to the rspec core, Liz Keogh (jbehave lead) for demanding that steps should take parameters and not taking no for an answer. Also PragDave ran an inspiring meta-programming workshop at QCon that gave me the courage to try this stuff.

Filed under: BDD, ruby — Dan North @ 10:23 pm

February 12, 2007

Behaviour-driven stories

At a recent software architecture workshop, I was discussing the ideas behind BDD with a great group of people (more about that soon). One theme that kept coming up was the fact that I needed to write much more about BDD as an entire methodology, and to address the current perception that it is just a repackaging of test-driven development (which, to be fair, is where it started).

As I was describing the workings of BDD, I discovered that I had made the assumption that everyone knew what a Story was, in the agile sense of defining a requirement. It turns out that there’s a whole world outside of my little bubble that use all sorts of different processes for identifying and defining requirements, and in particular they don’t know what I mean by a Story, nor why they should care.

I was specifically asked what a story was from a behaviour-driven perspective, so I have written it up in an article called What’s in a Story?.

In the interests of releasing early and often, I will be editing and updating it in response to comments on this post. I’m particularly interested in people’s thoughts about how BDD stories compare to Use Cases. I’ve read a bit about use cases and used them a long time ago, but I haven’t been around them recently enough to really remember whether I liked them.

Filed under: BDD, agile, articles — Dan North @ 12:42 am

October 20, 2006

Article: Introducing Behaviour-Driven Development

At the beginning of this year I wrote a feature article for Better Software magazine, which was published as “Behavior Modification” back in March.

The article is now available on my site. It gives an overview of behaviour-driven development, from its origins as a coaching aid for TDD through to its current form as a proven, comprehensive development approach.

Filed under: BDD, agile, articles — Dan North @ 6:22 pm

June 4, 2006

There’s more to BDD than evolving TDD

Behaviour-driven development started life as an NLP exercise to stem the abuse of the word “test” in “test-driven development”. Since then it has grown into a respectable and proven agile methodology (with a small “m” of course).

Dave Astels, the award-winning author, was an early adopter of BDD and has been instrumental in raising its profile. He presented it at Canada on Rails and is taking it to JAOO and SD Best Practices. He has even presented it to Google. His Ruby BDD framework, rspec, has inspired a number of similar projects.

Now, Dave is a programmer. What’s more, he is a very thoughtful programmer, which means he invests a lot of energy in making programming productive and effective – and more importantly fun – for himself and other programmers. He doesn’t get very excited about capturing requirements or the dynamic between testers and analysts, so you won’t hear him talking about the wider context of BDD, but you will hear him saying that there is one!

BDD is fundamentally about identifying behaviour. At the analysis level, the behaviour of a story is its acceptance criteria, which BDD expresses in the form of automated scenarios. You need analysts working with testers to capture the stories and identify the acceptance criteria, and then you need programmers working with testers to automate the scenarios.

So the ironic twist is that all that talk about “testing” in TDD was taking the focus off the real testing action! My efforts to put the word “test” back in its box have in fact propelled the testers into the central role on a BDD team.

So the message here is twofold. Firstly, although a lot of the existing BDD message is in the TDD space, don’t lose sight of the bigger picture or you’ll miss out on all the good stuff. And secondly don’t underestimate the value of the testers on your team: they are your direct line to delivering high value software.

Filed under: BDD, agile, programming — Dan North @ 11:24 pm

March 19, 2006

BDD article published in Better Software magazine

So, it’s taken me two years to finally get round to writing down what behaviour-driven development is all about, but I’m pleased with the result. The article has just been published in the March edition of Better Software as “Behavior ((I didn’t quite get away with the UK spelling)) Modification”.

I started talking about BDD as an evolution of TDD at the back end of 2003, and played with the idea of a BDD framework, in the form of JBehave, during 2004. I made some noise about it at the Agile Developers’ Conference in June 2004, and then at the end of the year everything went kind of quiet. That’ll teach me to have a day job.

At the end of last year, I finally got back into BDD evangelist mode, and decided to write the story of behaviour-driven development: where it came from, what it’s about, how it has grown and where it is going. Just when I was busy working out what I wanted to say, by a curious coincidence, Brian Marick approached me to write an article about BDD and JBehave for his excellent magazine, Better Software, which I was targeting as my ideal audience anyway. Hurrah!

You know what to do – rush to the StickyMinds.com site and take out a subscription so you can read the article and tell all your friends about it.

I have to thank Brian and his excellent editorial team, as well as the ThoughtWorkers who gently (!) shepherded me through the process of writing and editing the article. In particular, Liz Keogh, Martin Fowler (yes, that one), Joe Walnes and Rebecca Parsons were extremely helpful and supportive. Thanks guys.

Filed under: BDD — Dan North @ 10:15 pm
« Previous PageNext Page »

Powered by WordPress