Install RSpec for Ruby on Rails 3
Install Rspec-rails
sudo gem install rspec-rails
- RSpec is a behavior driven development (BDD) framework for low level testing in the Ruby language
Using RSpec to Test a Rails 3 Application
Create a new Rails application store
Edit the Gemfile
Include the Cucumber gems in a Rails 3 application
group :test, :development do
gem "rspec-rails", "~> 2.4"
gem 'capybara'
end
Install the Gems
Edit the DB connection information and put the valid DB configuration information
Create the MySQL DB
rake db:create
rake db:migrate
Bootstrap a Rails 3 application with RSpec
rails generate rspec:install
create .rspec
create spec
create spec/spec_helper.rb
Testing Ruby on Rails Application with RSpec
Generate a model
rails generate model order name:string
invoke active_record
create db/migrate/20110510190917_create_orders.rb
create app/models/order.rb
invoke rspec
create spec/models/order_spec.rb
Create the DB table
General Syntax for RSpec
describe "something" do
it "does something" do
...
end
end
describe "something" do
context "in one context" do
it "does something" do
...
end
end
context "in another context" do
...
end
end
Edit the RSpec Test
vi spec/models/order_spec.rb
Edit the RSpec testing code
require 'spec_helper'
describe Order, "shipping methods" do
it "returns the order's shipping mode" do
order = Order.create!
order.shipping = 'express'
order.shipping.should == 'express'
end
end
Smoke test
RSpec Core
Create a helper method for the test
let(:count) { @total += 1 }
Before, After & Around
Run test setup code
before(:each) do
@order = Order.new
end
Before and after test setup
before(:each) # run before each test
before(:all) # run one time only
after(:each) # run after each test
after(:all) # run one time only
A around test setup
class Tx
def self.transaction
puts "open tx"
yield
puts "close tx"
end
end
describe "around filter" do
around(:each) do |example|
Tx.transaction(&example)
end
...
end
RSpec Matcher
RSpec should and should_not Syntax
order.should matcher(expected)
order.should_not matcher(expected)
Example
"A".should eq("A")
"A".should_not eq("B")
Check if empty or exist in RSpec
[].should be_empty
[1].should_not be_empty
test_result.should exist
test_result.should_not exist
Check the type in RSpec
120.should be_a_kind_of(Fixnum)
Check specific values in RSpec
test_result.should be
test_result.should be_true
test_result.should be_false
test_result.should be_nil
test_result.should_not be_nil
test_result.should eql(1)
test_result.should_not eql(1)
Collection key checking in RSpec
{:a => "A"}.should have_key(:a)
Check the collection size in RSpec
# Passes if test_result.orders.size == 11
test_result.should have(10).orders
# Passes if [1,2].length == 2
[1,2].should have(2).items
[1,2].should have >= 1
# Check string length
"1234".should have(4).characters
Check result within 0.5 of 3.0
test_result.should be_close(3.0, 0.5)
Check array content in RSpec
[1,2,3,4,5].should include(2,3)
Verify test result with regular expression in RSpec
test_result.should match(/[0-9]+)
Check if an exception is raised in RSpec
lambda { some_action }.should raise_error
lambda { some_action }.should raise_error(SomeError)
lambda { some_action }.should raise_error(SomeError) { |error| ... }
lambda { some_action }.should raise_error(SomeError, "some errors happened")
RSpec Mock Up
RSpec provides mock up objects used for testing
Create a RSpec double object
double_order = double("Order")
- double means create a Mock up (Not the floating value)
Alternatively, use the stub method to create a Mock up object with a stub method
obj.stub(:text).and_return('evaluated the return value immediately')
obj.stub(:text) { 'evaluated the value when it is called' }
obj.text.should eq('evaluated the value when it is called')
- Create a method text for the Mock up double object
- Return a value for the method price
Create a RSpec object return a value in a mock up method
describe "a mock up object" do
it "returns a value" do
object = Object.new
object.stub(:value) do |arg|
if arg == 1
"odd"
elsif arg == 2
"eve"
end
end
object.value(1).should eq("odd")
object.value(2).should eq("even")
end
end
Raise an exception in the RSpec double
obj.stub(:value).and_raise("something_wrong")
obj.stub(:value).and_throw(:something_wrong)
RSpec Message Expectation
obj.value is expected to be called during the testing
obj.should_receive(:value)
# obj.value will retun "this ... return"
obj.should_receive(:value) { 'this is the value to return' }
Trace method calls with Mock up double in RSpec
describe Order do
context "when closed" do
it "logs an 'order shipped' message" do
logger = double()
order = Order.new
order.logger = logger
logger.should_receive(:order_shipped).with(order)
order.ship
end
end
end
- Create a logger double and assigned it to the order's logger
- should_receive will assert true if order.ship call logger.order_shipped with order as the parameter
Count the number of calls
obj.should_receive(:value).twice
obj.should_receive(:value).exactly(2).times
obj.should_receive(:value).at_least(:once)
obj.should_receive(:value).at_least(2).times
obj.should_receive(:value).at_most(:twice)
obj.should_receive(:value).at_most(2).times
Raise exception
obj.should_receive(:value) { raise "some error" }
obj.should_receive(:value) { throw :some_error }
RSpec Rails
RSpec Model Spec
Use RSpec to test Rails' Model
require "spec_helper"
describe Order do
context "with 2 or more items" do
it "display order items" do
order = Order.create
item1 = order.item("item 1")
item2 = order.item("item 2")
order.reload.items.should eq([item1, item2])
order.should have(2).errors_on(:name)
end
end
end
RSpec Controller Spec
Test Rails' controller using RSpec
describe OrdersController do
describe "GET index" do
it "assigns @orders" do
order = Order.create
get :index
assigns(:orders).should eq([order])
end
it "renders the index template" do
get :index
response.should render_template("index")
end
end
end
RSpec Request Spec
Use RSpec to test HTTP request
require "spec_helper"
describe "Order management" do
it "creates an Order and redirects to the Order's index page" do
get "/orders/new"
response.should render_template(:new)
post "/orders", :order => {:name => "Order 1"}
response.should redirect_to(assigns(:order))
follow_redirect!
response.should render_template(:show)
response.body.should include("Order was successfully created.")
end
end
- render_template verifies what view is rendered
- redirect_to verifies the redirection
RSpec Route Spec
Use RSpec to verify rails routing
{ :get => "/orders/24444/ship" }.
should route_to(
:controller => "orders",
:action => "index"
)
Verify that the route is not available
{ :delete => "/orders/24444" }.should_not be_routable
RSpec View Spec
Use RSpec to test the View
require "spec_helper"
describe "orders/index.html.erb" do
it "displays all the orders" do
assign(:orders, [
stub_model(Order, :name => "order 1"),
stub_model(Order, :name => "order 2")
])
render
rendered.should =~ /order 1/
rendered.should =~ /order 2/
end
end
mock_model & stub_model
Create a Mock up model object similar to ActiveRecord
require "spec_helper"
describe "mock_model Order" do
let(:order) do
mock_model Order, :value => "something",
:save => true
end
it "access the value method" do
order.vale.should eq("something")
end
it "access ActiveRecord method" do
order.save.should eq(true)
end
end
Generate an instance of ActiveRecord
let(:order) do
stub_model Order, :id => 10
end
|