BDD In Ruby

To understand the difference between TDD and BDD developers must concentrate on specifying application behavior instead of verifying it.
This thought is described in this Dave Astels' text: http://blog.daveastels.com/files/BDD_Intro.pdf

Thus BDD specifications will substitute old tests on your new apps.

  • Instead of a /test directory you now will have a /spec directory.
  • Instead of rake test you will run rake spec.

The way to template your files is

script/generate rspec_model MyModelClass
exists app/models/
create spec/models/
create spec/fixtures/
create app/models/my_model_class.rb
create spec/models/my_model_class_spec.rb
create spec/fixtures/my_model_class.yml
create db/migrate
create db/migrate/20090402160952_create_my_model_class.rb

Some of the methods that RSpec offers are:
‣ should_equal(expected)
‣ should_not_equal(expected)
‣ should_be_same_as(expected)
‣ should_not_be_same_as(expected)
‣ should_match(expected)
‣ should_not_match(expected)
‣ should_be_nil()
‣ should_not_be_nil()
‣ should_be_empty()
‣ should_not_be_empty()
‣ should_include(sub)
‣ should_not_include(sub)
‣ should_be_true()
‣ should_be_false()

Here Dave Astel's guidelines are very interesting:

Name your Context classes by what they are focused on: EmptyMovieList and One-MovieList, for example. They contain only specification method directly related to that context.
Name your specification methods by the focus of that specification, e.g. should_have_size_of_0.
Together, the names of the Context class (the files containing the specifications) and expectation method should read well, to tell you exactly with is going on: EmptyMovieList.should_have_size_of_0. Just think of how easy it would be to extract a specification document from this.
Your specification methods should be as simple, short, and focused as you can make them. One expectation… excellent… that should be your holy grail. Simple is good. It’s far better to have lots of small, simple, focused, understandable classes and methods than fewer large, bloated classes and long, complex methods.

Examples

it "should enforce the existence of mandatory fields" do
  lambda{ Profile.create!() }.should raise_error("Validation failed: Min meters can't be blank, Min rooms can't be blank, Max price can't be blank")
end
 
it "should enforce the existence of min_meters" do
  @valid_attributes.delete(:min_meters)
  lambda{ Profile.create!(@valid_attributes) }.should raise_error("Validation failed: Min meters can't be blank")
end
 
it "should enforce the existence of min_rooms" do
  @valid_attributes.delete(:min_rooms)
  lambda{ Profile.create!(@valid_attributes) }.should raise_error("Validation failed: Min rooms can't be blank")
end
 
it "should enforce the existence of max_price" do
  @valid_attributes.delete(:max_price)
  lambda{ Profile.create!(@valid_attributes) }.should raise_error("Validation failed: Max price can't be blank")
end
 
 it 'should not accept prices greater than max_price' do
  profile= Profile.create(@valid_attributes)
  profile.check_price(101).should be_false
  profile.check_price(102).should be_false
  profile.check_price(200).should be_false
  profile.check_price(2000).should be_false
  profile.check_price(999).should be_false
 end
 
 it 'should accept prices equal or lower than max_price' do
  profile= Profile.create(:max_price => 100)
  profile.check_price(100).should be_true
  profile.check_price(99).should be_true
  profile.check_price(9).should be_true
 end

Installing RSpec

Here I've choosen to install RSpec but there's also the Factory Girl BDD framework which can be used.

One must start by configuring the gem on the application. To so so we can follow the steps explained [on github http://wiki.github.com/dchelimsky/rspec/configgem-for-rails].

config.gem (for Rails)

Issues related to configuring rspec gems in rails 2.2 (see “Check the configuration” section below for NOTES:) and 2.3 have been substantially resolved in the rspec-rails1.2.0 release.

Here are the steps to upgrade to the 1.2.0 gems on a Mac.

Install the 1.2 gems

[sudo] gem install rspec
[sudo] gem install rspec-rails

Remove the old rspec libs from the app

If you’ve got rspec, rspec-rails, dchelimsky-rspec, or dchelimsky-rspec-rails installed in vendor/gems or vendor/plugins, get rid of them (or set them aside in case you need to roll back this process).
Remove the old rspec.rake file

rm lib/tasks/rspec.rake

The old rspec.rake file is the source of most of the problems that people have experienced with configuring rspec gems in the past. It depended on rspec, so we had a catch 22 that manifested itself in numerous ways. For example, if the project didn’t bundle the gems, and you cloned the project to a new environment with no rspec installed, none of the rake tasks would work because rake would load up rspec.rake and errors would follow. That’s just one of many. Trust me – get rid of it.

Configure the gems

# in config/environments/test.rb
config.gem "rspec", :lib => false, :version => ">= 1.2.0"
config.gem "rspec-rails", :lib => false, :version => ">= 1.2.0"

NOTES:

  • use :lib => false, as we don’t need rails to ever load the libs for you (it’s managed by the rake tasks)

Check the configuration

$ rake gems RAILS_ENV=test
 - [I] rspec = 1.2.0
 - [I] rspec-rails = 1.2.0

NOTES:

  • Some people have reported to receive an error relating to dependencies (something that looks like this) when using rails 2.2. If you have the option, use rails >= 2.3, which should resolve the problem. If you do not have the option to use rails >= 2.3, then one solution is patching your lib/rails/gem_dependency.rb dependencies function with something like return [] if nil.

Bundle the gems

This part is entirely optional. If you want to bundle the gems in the app (in vendor/gems) as well, do this:

$ sudo rake gems:unpack RAILS_ENV=test
$ sudo rake gems:unpack:dependencies RAILS_ENV=test

IMPORTANT: Regenerate the rspec files

$ script/generate rspec

You MUST allow this to update the following generated files:

  • lib/tasks/rspec.rake
  • script/spec
  • script/spec_server

You need not allow this to update spec/spec_helper.rb if you have any customizations, but if you do, change the line that reads:

require 'spec'

to

require 'spec/autorun'
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License