RSpec step-by-step tutorial
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 "http://rubygems.org"
gem "rspec", "1.3.1"
gem "activesupport", "3.0.5"
And Rakefile:
require 'rake'
require 'spec/rake/spectask'
desc "Run all examples"
Spec::Rake::SpecTask.new('test') do |t|
t.spec_files = FileList['test/**/*.rb']
end
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 = Log.new(LOGFILEPATH)
end
after(:all) do
File.delete(LOGFILEPATH)
end
it "should exist after instantiation" do
File.exist?(LOGFILEPATH).should be_true
end
it "shouldn't be overwrittean after re-instantiation" do
@log.log_write "Hello World"
@log.close
@log = nil
@log = Log.new(LOGFILEPATH)
File.size(LOGFILEPATH).should > 0
end
end
And to lib/log.rb:
class Log
def initialize(filename)
@file = File.open(filename, "a")
end
def log_write(text)
@file.write(text+"\n")
end
def close
@file.close
end
end
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
end
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')
'http://fr.ivolo.us'.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:
https://github.com/czettnersandor/Rspec-Log-testing-tutorial
Comments