In the previous post
Do it RSpec the usage of RSpec in a Ruby project was described generally. This post explains how to code a simple RSpec test in a Ruby on Rails project.
The installation of RSpec itself is alike:
user$ gem install rspec
In a Rails project the rspec-rails gem has to be added to the Gemfile:
gem "rspec-rails", :group => [:test, :development]
Runing the Bundler:
user$ bundle
and preparing the Rails project for RSpec tests:
user$ rails g rspec:install
It generates the subfolder spec and a spec helper within. The spec helper file contains logic considering all tests.
At this point only testing models is covered. That's why creating the folder:
user$ mkdir spec/models
Generating the model:
user$ rails g model Person name:string surname:string birthday:date active:boolean
The generated models/person.rb looks blank like:
class Person < ActiveRecord::Base
attr_accessible :birthday, :name, :surname, :active
end
Some tests require test objects, called fixtures. Creating the folder for them:
user$ mkdir spec/fixtures
Fixtures are defined in a YAML notation, e.g.:
david:
id: 1
name: David
surname: Heinemeier Hansson
birthday: 1979-10-15
Saving this single fixture in the file spec/fixtures/people.yml. Please keep in mind, the more fixtures you create for several tests the harder to maintain changes of fixtures.
Creating the spec/models/person_spec.rb:
require 'spec_helper'
describe Person do
fixtures :people
before(:each) do
@person = people(:david)
end
it "should not be valid without a name" do
@person.name = ''
@person.should_not be_valid
end
it "should be activated before validation" do
@person.create.should be_active
end
end
That are pretty little specifications. Before fullfilling them, the test was run:
user$ rspec spec/models/person_spec.rb
it returns:
Failures:
1) Person should not be valid without a name
Failure/Error: @person.should_not be_valid
expected valid? to return false, got true
# ./spec/models/person_spec.rb:12:in `block (2 levels) in '
2) Person should be activated before validation
Failure/Error: @person.should be_active
expected active? to return true, got false
# ./spec/models/person_spec.rb:17:in `block (2 levels) in '
Finished in 0.09145 seconds
2 examples, 2 failures
Implementing the logic to achieve the goals by enhancing the models/person.rb:
class Person < ActiveRecord::Base
attr_accessible :birthday, :name, :surname, :active
validates_presence_of :name
end
Again the test:
Failures:
1) Person should be activated before validation
Failure/Error: @person.should be_active
expected active? to return true, got false
# ./spec/models/person_spec.rb:17:in `block (2 levels) in '
Finished in 0.17313 seconds
2 examples, 1 failure
First requirement is satisfied. Enhancing the same model to strike the second:
class Person < ActiveRecord::Base
attr_accessible :birthday, :name, :surname
validates_presence_of :name
before_validation :activate
private
def activate
self.active = true
end
end
Running the tests again:
Finished in 0.11393 seconds
2 examples, 0 failures
signals: mission accomplished!
Supported by Ruby 2.1, RubyOnRails 3.2.17 and RSpec 2.12.0