Book on BDD in Ruby with RSpec

RSpec book

I was browsing through this excellent presentation given by Dave Astels and David Chelimsky at RubyConf2007. Turns out that David Chelimsky and Aslak Helles√ły are working on a book about Behaviour Driven Development using RSpec.

The presentation is an excellent introduction for anyone thinking about moving to RSpec. It tells you a bit about the (rather short) history of the framework and the differences between BDD and TDD.

It also shows off the awesome plain-text stories I posted about earlier.

Behaviour Driven Development

I’m currently doing an internship as a final part of my study. Luckily I’ve been able to find a company where I can use Rails to create a new application.

One of the choices I made for the development is the use of BehaviourDrivenDevelopment (BDD), which is a variation on TestDrivenDevelopment (TDD).

Rspec is a BDD-framework for Rails. It features a beautiful way of expressing the expected behaviour of your application.

Here’s an example of the expected behaviour of a user controller

  it "should flash a notice after succesful signup" do
    User.should_receive(:new).with({"name" => 'Arie'}).and_return(@user)
    @user.should_receive(:save!)
    post 'signup', {:user => {:name => 'Arie'}}
    flash[:notice].should eql(_('Thanks for signing up, you will have to activate your account before you can log in'))
  end

And an example of expected behaviour of a user model

  specify "should be invalid with invalid zip code" do
    @user.attributes = valid_user_attributes.except(:zip)
    @user.zip = 'tralalalalala'
    @user.should_not be_valid
    @user.errors.on(:zip).should eql(_('is invalid'))
    @user.zip = '1234AB'
    @user.should be_valid
  end

The main idea of TDD and BDD is that you write these tests or specifications before writing the actual code. The basic workflow while doing BDD/TDD is:

1. Write tests/specifications

2. Run tests/specifications

3. See them fail because there’s no code yet

4. Code until tests no longer fail

It takes some discipline to strictly follow this pattern, because a future piece of code might seem so trivial, that you want to code it immediately.

rcov resultsWriting the specifications like this takes some time, but you’ll easily make up for it while you’re coding your application. You can use Rcov to check if your specifications cover all your code. When your specifications cover all your code with sensible tests, you can easily refactor your code, because the specifications will make sure your new code works properly.

Also, you can generate human-readable specifications from these rspec files, here’s a snippet of how that looks:

A user
– should be invalid without a username
– should have unique login name
– should be invalid without an email
– should be invalid if email is not between 3 and 100 characters in length
– should have unique email address

The UserController
– should redirect to profile after successfull activation
– should flash a notice when a valid activation code was used
– should flash an error when an invalid activation code was used

In combination with AutoTest, BDD is already saving me a lot of time during development.

Whenever I’ve changed some of my sourcecode or specifications, the specifications get tested automatically. If something breaks, there’s a small error popup, so you know you should check the AutoTest window for the test where it failed.

autotest error

Spot the typo

‘The User Controller should flash an error when an invalid activation code was used‘ FAILED
expected “Unable to activate the account.”, got “Unable to activate the accnt.” (using .eql?)

./spec/controllers/user_controller_spec.rb:29:
script/spec:4:

If all tests pass you get a cheerful message.

AutoTest success