RSpec step-by-step tutorial

2 minute read

My last PHP tutorial was about PHPUnit tests. Now let’s learn about the more elegant Ruby BDD/TDD framework, named rspec.

I’m using a newly installed Archlinux. First, install sstephenson’s Ruby Version Management software:

$ yaourt rbenv
$ yaourt ruby-build-git

Now, build ruby the proper way:

$ rbenv install 1.9.2-p290
$ ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]

Install bundler, the best way to define GEM requirements in project level:

$ sudo gem install bundler

Create the project directory and some initial files:

$ mkdir rspec-tutorial
$ mkdir test
$ mkdir lib
$ touch Rakefile
$ touch Gemfile

Edit Gemfile:

source ""
gem "rspec", "1.3.1"
gem "activesupport", "3.0.5"

And Rakefile:

require 'rake'
require 'spec/rake/spectask'

desc "Run all examples"'test') do |t|
  t.spec_files = FileList['test/**/*.rb']

Install all required gems by typing: “bundle install”. Now, if you put “rake test” in command line, the test will run with no output (there are no test cases). Let’s create some application logic. I will re-implement my PHP Log class described before. Put this to test/log_spec.rb:

require './lib/log.rb'
LOGFILEPATH = '/tmp/loggertest.log'

describe Log do
  before(:all) do
    @log =
  after(:all) do
  it "should exist after instantiation" do
    File.exist?(LOGFILEPATH).should be_true
  it "shouldn't be overwrittean after re-instantiation" do
    @log.log_write "Hello World"
    @log = nil
    @log =
    File.size(LOGFILEPATH).should > 0

And to lib/log.rb:

class Log
  def initialize(filename)
    @file =, "a")
  def log_write(text)
  def close

As you can see, the rspec test examples have a very readable syntax:

  it "should exist after instantiation" do
    File.exist?(LOGFILEPATH).should be_true

But what is before(:all) and after(:all) does mean? Everything in the do-end block will execute once. Before starting testcase and after all test examples done in the file. You can also use the “:each” when you want to execute anything every time a test example run.

Some other assertions:

  'foo'.should == 'foo'
  'foo'.should === 'foo'
  'foo'.should_not equal('foo')
  ''.should be_empty
  'foo with bar'.should include('with')
  ''.should match(/http:\/\/.+/i)
  nil.should be_nil
  100.should < 200
  200.should >= 100
  (200 - 100).should == 100
  # (100 - 80) is less than 21

  100.should be_close(80,21)
  [1,2,3].should have(3).items
  [].should be_empty
  [1,2,3].should include(2)
  {}.should be_empty
  {:post => {:title => 'test'}}.should have_key(:post)
  {:post => {:title => 'test'}}.should_not have_key(:title)
  false.should be_false
  true.should be_true
  @post.should be_instance_of(Post)
  @post.should respond_to(:title)

Feel free to try everything you want and define more “it must be work, should be true” sentences, run them and create bigger applications with team-players like you. Next, we will see “Cucumber”.

Whole source code available here: