Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

379 lines (321 sloc) 11.144 kB
# RSpec Examples (RSpec Book, The Rails 3 Way, Custom)
################################################################################
# command line
# rspec --help (show help)
# rake -T spec (list all rspec-rails rake tasks)
# rspec spec (run all specs in spec folder)
# rspec spec/models/user_spec.rb (run only user_spec)
# rake spec:models (rails: run all model specs)
################################################################################
# configuration
# global before/after/around hooks
# (:each, :all, :suite)
RSpec.configure do |config|
config.after :suite do
Mongoid.master.collections.select do |collection|
collection.name !~ /system/
end.each(&:drop)
end
end
# inclusion filter
RSpec.configure do |c|
c.filter = { :focus => true }
end
describe "group" do
it "example 1", :focus => true do
end
end
# exclusion filter
RSpec.configure do |c|
c.exclusion_filter = { :slow => true }
end
describe "group", :slow => true do
it "example 1" do
end
it "example 2" do
end
end
# lambda filter
require 'ping'
RSpec.configure do |c|
c.exclusion_filter = {
:if => lambda { |what|
case what
when :network_available
!Ping.pingecho "example.com", 10, 80
end
}
}
end
describe "network group" do
it "example 1", :if => :network_available do
end
it "example 2" do
end
end
################################################################################
# describe/context (describe for things, context (alias) for context)
describe User do
context "#create" do
end
end
################################################################################
# pending (instead of adding comment to disable example)
describe User do
before { pending }
it "should be successful" do
end
end
describe "an empty array" do
it "should be empty" do
pending("bug report 18976") do
[].should be_empty
end
end
end
################################################################################
# before, after, around (before(:each) executed before each example)
describe Stack do
context "when empty" do
before(:each) do
@stack = Stack.new
end
end
end
################################################################################
# helper methods
describe Thing do
def create_thing(options)
thing = Thing.new
thing.set_status(options[:status])
thing
end
end
describe Thing do
def given_thing_with(options)
yield Thing.new do |thing|
thing.set_status(options[:status])
end
end
it "should do something when ok" do
given_thing_with(:status => 'ok') do |thing|
thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
end
end
end
################################################################################
# helper modules
module UserExampleHelpers
def create_valid_user
User.new(:email => 'email@example.com', :password => 'shhhhh')
end
end
describe User do
include UserExampleHelpers
it "does something when it is valid" do
user = create_valid_user
end
end
# or include in all example groups
RSpec.configure do |config|
config.include(UserExampleHelpers)
end
################################################################################
# shared examples
# spec/support/shared_examples.rb
shared_examples_for "a phone field" do
it "has 10 digits" do
Business.new(phone_field => '8004567890').should
have(:no).errors_on(phone_field)
end
end
describe "phone" do
let(:phone_field) { :phone }
it_should_behave_like "a phone field"
end
################################################################################
# let (instead of instance variables in before block)
let(:blog_post) { BlogPost.create :title => 'Hello' }
let!(:comment) { blog_post.comments.create :text => 'first post' }
################################################################################
# specify (generated descriptions)
# instead of repeating expectation with: it "should not be published"...)
specify { blog_post.should_not be_published }
################################################################################
# subject (delegate should/should_not to subject)
subject { BlogPost.new :title => 'foo', :body => 'bar' }
it "sets published timestamp" do
subject.publish!
subject.should be_published
end
it { should be_valid }
its(:errors) { should be_empty }
its(:title) { should == 'foo' }
its(:body) { should == 'bar' }
its(:published_on) { should == Date.today }
################################################################################
# matchers
# be
target.should be
target.should be_true
target.should be_false
target.should be_nil
target.should_not be_nil
thing.should be # passes if thing is not nil or false
collection.should be_empty # passes if target.empty?
target.should_not be_empty # passes unless target.empty?
target.should_not be_under_age(16) # passes unless target.under_age?(16)
user.should be_in_role("admin") # passes if user.in_role?("admin") returns true
result.should be_close(5.25, 0.005)
# be_a, be_an
"a string".should be_an_instance_of(String)
3.should be_a_kind_of(Fixnum)
3.should be_a_kind_of(Numeric)
3.should be_an_instance_of(Fixnum)
3.should_not be_instance_of(Numeric) #fails
# operators
result.should == 3
result.should =~ /some regexp/
result.should be < 7
result.should be <= 7
result.should be >= 7
result.should be > 7
# include
[1, 2, 3].should include(1)
[1, 2, 3].should_not include(4)
"foobar".should include("bar")
"foobar".should_not include("baz")
# have
{:foo => "foo"}.should have_key(:foo)
{:bar => "bar"}.should_not have_key(:foo)
"this string".should have(11).characters
[1, 2, 3].should have(3).items
schedule.should have(3).days # passes if schedule.days.length == 3
home_team.should have(9).players_on(field) # delegates players_on to home_team
widget.should have(1).error_on(:name)
model.should have(:no).errors_on(:title)
model.should have(1).record
day.should have_exactly(24).hours
dozen_bagels.should have_at_least(12).bagels
internet.should have_at_most(2037).killer_social_networking_apps
# respond_to
list.should respond_to(:length)
# errors
lambda { Object.new.explode! }.should raise_error(NameError)
# when all else fails...
actual.should satisfy { |actual| block } # passes if block returns true
################################################################################
# expect
# for changes
expect { BlogPost.create :title => "Hello"}.to change { BlogPost.count }.by(1)
expect { seller.accept Offer.new(250_000) }.to change{agent.commission}.by(7_500)
expect { blog_post.publish! }.to change { blog_post.published_on }.from(nil).to(Date.today)
expect { subject.update_with_omniauth(omniauth) }.to_not change { subject.score }
# for errors
expect { do_something_risky }.to raise_error
expect { account.withdraw 75, :dollars }.to raise_error(/attempted to withdraw 75 dollars/)
expect { account.withdraw 75, :dollars }.to raise_error(InsufficientFundsError)
course = Course.new(:seats => 20)
20.times { course.register Student.new }
lambda {
course.register Student.new
}.should throw_symbol(:course_full, 20)
################################################################################
# custom matcher dsl
# joe.reports_to?(beatrice).should be_true
joe.should report_to(beatrice)
RSpec::Matchers.define :report_to do |boss|
match do |employee|
employee.reports_to?(boss)
end
end
################################################################################
# doubles/stubs/mocks (aliases)
# doubles/stubs: method stubs (stub(:method).and_return(data))
# mocks: expectations (should_receive...)
describe Statement do
it "uses the customer's name in the header" do
customer = double('customer')
customer.stub(:name).and_return('Aslak')
statement = Statement.new(customer)
statement.generate.should =~ /^Statement for Aslak/
end
end
# shortcut
customer = double('customer', :name => 'Aslak')
# null object
null_object = mock('null', :null_object => true)
# fakes
ages = double('ages')
ages.stub(:age_for) do |what|
if what == 'drinking'
21
elsif what == 'voting'
18
end
end
# stub chains
article = double()
Article.stub_chain(:recent, :published, :authored_by).and_return(article)
# partial stubbing/mocking
describe WidgetsController do
describe "PUT update with valid attributes" do
# partial stubbing
it "redirects to the list of widgets" do
widget = Widget.new()
Widget.stub(:find).and_return(widget)
widget.stub(:update_attributes).and_return(true)
put :update, :id => 37
response.should redirect_to(widgets_path)
end
# partial mocking
it "updates the widget's attributes" do
widget = Widget.new()
Widget.stub(:find).and_return(widget)
widget.should_receive(:update_attributes).and_return(true)
put :update, :id => 37
end
end
end
# expectations
echo = mock('echo')
echo.should_receive(:sound).with("hey").and_return("hey")
echo.should_receive(:sound).with("hey") { "hey" }
mock_account.should_receive(:withdraw).exactly(1).times
network_double.should_receive(:open_connection).at_most(5).times
network_double.should_receive(:open_connection).at_least(2).times
account_double.should_receive(:withdraw).once
account_double.should_receive(:deposit).twice
checking_account.should_receive(:transfer).with(50, savings_account)
source_account.should_receive(:transfer).with(target_account, instance_of(Fixnum))
source_account.should_receive(:transfer).with(anything(), 50)
source_account.should_receive(:transfer).with(any_args())
collaborator.should_receive(:message).with(no_args())
mock_account.should_receive(:add_payment_accounts).with(hash_including('Electric' => '123', 'Gas' => '234'))
mock_account.should_receive(:add_payment_accounts).with(hash_not_including('Electric' => '123', 'Gas' => '234'))
mock_atm.should_receive(:login).with(/.* User/)
network_double.should_not_receive(:open_connection)
network_double.should_receive(:open_connection).never
# ordering (ensure count is called before add)
database.should_receive(:count).with('Roster', :course_id => 37).ordered
database.should_receive(:add).with(student).ordered
# errors
account_double.should_receive(:withdraw).and_raise
account_double.should_receive(:withdraw).and_raise(InsufficientFunds)
account_double.should_receive(:withdraw).and_throw(:insufficient_funds)
# custom argument matchers
class GreaterThanMatcher
def initialize(expected)
@expected = expected
end
def description
"a number greater than #{@expected}"
end
def ==(actual)
actual > @expected
end
end
def greater_than(floor)
GreaterThanMatcher.new(floor)
end
calculator.should_receive(:add).with(greater_than(37))
Jump to Line
Something went wrong with that request. Please try again.