RSpec 的官网是 https://www.relishapp.com/rspec
从那里我们可以知道 RSpec 实际由 4 部分组成:
- rspec-core
- rspec-expectations
- rspec-mocks
- rspec-rails
一、RSpec Expectations
Equivalence
actual.should eq(expected) # passes if actual == expected
actual.should == expected # passes if actual == expected
actual.should eql(expected) # passes if actual.eql?(expected)
Identity
actual.should be(expected) # passes if actual.equal?(expected)
actual.should equal(expected) # passes if actual.equal?(expected)
Comparisons
actual.should be > expected
actual.should be >= expected
actual.should be <= expected
actual.should be < expected
actual.should be_within(delta).of(expected)
Regular expressions
actual.should =~ /expression/
actual.should match(/expression/)
Types/classes
actual.should be_an_instance_of(expected)
actual.should be_a_kind_of(expected)
Truthiness
actual.should be_true # passes if actual is truthy (not nil or false)
actual.should be_false # passes if actual is falsy (nil or false)
actual.should be_nil # passes if actual is nil
Expecting errors
expect { ... }.to raise_error
expect { ... }.to raise_error(ErrorClass)
expect { ... }.to raise_error("message")
expect { ... }.to raise_error(ErrorClass, "message")
Expecting throws
expect { ... }.to throw_symbol
expect { ... }.to throw_symbol(:symbol)
expect { ... }.to throw_symbol(:symbol, 'value')
Predicate matchers
actual.should be_xxx # passes if actual.xxx?
actual.should have_xxx(:arg) # passes if actual.has_xxx?(:arg)
此外 RSpec::Matchers
还有:
Ranges (Ruby >= 1.9 only)
(1..10).should cover(3)
Collection membership
actual.should include(expected)
Examples
[1,2,3].should include(1)
[1,2,3].should include(1, 2)
{:a => 'b'}.should include(:a => 'b')
"this string".should include("is str")
二、RSpec Mocks
Test Doubles
book = double("book")
Method Stubs
book.stub(:title) { "The RSpec Book" }
book.stub(:title => "The RSpec Book")
book.stub(:title).and_return("The RSpec Book")
book = double("book", :title => "The RSpec Book")
double(:foo => 'bar')
order.calculate_total_price(stub(:price => 1.99),stub(:price => 2.99))
四、rspec-rails-2 (Request, Controller, View, Model, Routing, Helper, :Matchers)
Request Specs
describe "home page" do
it "diplays the user's username after successful login" do
user = User.create!(:username => "jdoe", :password => "secret")
get "/login"
assert_select "form.login" do
assert_select "input[name=?]", "username"
assert_select "input[name=?]", "password"
assert_select "input[type=?]", "submit"
end
post "/login", :username => "jdoe", :password => "secret"
assert_select ".header .username", :text => "jdoe"
end
end
describe "home page" do
it "diplays the user's username after successful login" do
user = Factory(:user, :username => "jdoe", :password => "secret")
visit "/login"
fill_in "Username", :with => "jdoe"
fill_in "Password", :with => "secret"
click_buton "Log in"
page.should have_selector(".header .username", :content => "jdoe")
end
end
Controller Specs
with fixtures
describe WidgetsController do
describe "GET index" do
fixtures :widgets
it "assigns all widgets to @widgets" do
get :index
assigns(:widgets).should eq(Widget.all)
end
end
end
with a factory
describe WidgetsController do
describe "GET index" do
it "assigns all widgets to @widgets" do
widget = Factory(:widget)
get :index
assigns(:widgets).should eq([widget])
end
end
end
with stubs
describe WidgetsController do
describe "GET index" do
it "assigns all widgets to @widgets" do
widget = stub_model(Widget)
Widget.stub(:all) { [widget] }
get :index
assigns(:widgets).should eq([widget])
end
end
end
matchers
response.should render_template(*args)
# => delegates to assert_template(*args)
response.should redirect_to(destination)
# => delegates to assert_redirected_to(destination)