這是一個(gè)簡單的關(guān)于Rails Rspec的簡單的介紹
1 安裝Rspec
在Rails的配置文件Gemfile配置文件中,配置下面信息
group :development, :test do
gem 'rspec-rails', '2.13.1'
end
我們沒有必要單獨(dú)的安裝RSpec ,因?yàn)樗莚spec-rails的依賴件
會(huì)被自動(dòng)安裝.
執(zhí)行bundle install 或者 bundle install --without production 來安裝使用的gem.
rails generate rspec:install
設(shè)置讓Rails使用RSpec 而不用Test::Unit. 該命令執(zhí)行完畢之后,會(huì)產(chǎn)生一個(gè)文件夾spec,該文件加下面有spec/spec_helper.rb 這個(gè)文件,spec_helper.rb用來設(shè)置測試的配置信息.
下面是spec的固定的規(guī)范,固定的格式.
describe XXX do
it XXX do
......
end
end
包含了一個(gè) describe 塊以及其中的一個(gè)測試用例(sample),以 it "..." do 開頭的代碼塊就是一個(gè)用例.
2 pending 測試大綱
describe xxxController do
describe 'GET #show' do
it "assigns the requested xxx to @xxx"
it "renders the :show template"
end
describe 'GET #new' do
it "assigns a new xxx to @xxx"
it "renders the :new template"
end
describe 'GET #edit' do
it "assigns the requested xxx to @xxx"
it "renders the :edit template"
end
describe "POST #create" do
context "with valid attributes" do
it "saves the new xxx in the database"
it "redirects to xxx#show"
end
context "with invalid attributes" do
it "does not save the new xxx in the database"
it "re-renders the :new template"
end
end
describe 'PUT #update' do
context "with valid attributes" do
it "updates the xxx in the database"
it "redirects to the xxx"
end
context "with invalid attributes" do
it "does not update the xxx"
it "re-renders the #edit template"
end
end
describe 'DELETE #destroy' do
it "deletes the xxx from the database"
it "redirects to users#index"
end
describe 'GET #index' do
it "response.status eq 200"
it "renders the :index view"
end
end
3 簡單的測試
測試代碼的結(jié)構(gòu)
describe AA do
it 'should do something' do
something.should
end
end
使用 http://railstutorial-china.org/ 里面的列子,來做一個(gè)簡單的測試演示.
rails generate controller StaticPages home help --no-test-framework
該命令會(huì)在app/controller文件下生成static_pages_controller.rb,并且會(huì)在路由里面生成help,home對應(yīng)的路由.
match '/help', to: 'static_pages#help', via: 'get'
match '/home', to: 'static_pages#home', via: 'get'
之后運(yùn)行下面命令,產(chǎn)生spec/requests/static_pages_spec.rb
rails generate integration_test static_pages
或者直接手動(dòng)創(chuàng)建spec/requests/static_pages_spec.rb這個(gè)文件.
下面做一個(gè)簡單的測試
describe "Home page" do
it "should have the content 'Sample App'" do
visit '/static_pages/home'
expect(page).to have_content('Sample App')
end
end
運(yùn)行bundle exec rspec spec/requests/static_pages_spec.rb, 運(yùn)行失敗!
因?yàn)樵?em>app/views/static_pages/home.html.erb文件中并沒有"Sample App"關(guān)鍵字.在該文件中,添加上"Sample App"測試就能通過.
4 let和let!的用法
Use let to define a memoized helper method. The value will be cached
across multiple calls in the same example but not across examples.
Note that let is lazy-evaluated: it is not evaluated until the first time
the method it defines is invoked. You can use let! to force the method's
invocation before each example.
http://stackoverflow.com/questions/10173097/rails-rspec-difference-between-let-and-let
使用let來定義一個(gè)memoized helper方法。該值可以在多個(gè)例子中使用,但不能跨多個(gè)實(shí)例調(diào)用。
-
spec/helpers/let_spec.rb *
describe "let" do
other_count = 0
invocation_order = []let(:count) do
invocation_order << :let!
other_count += 1
endit "calls the helper method in a before hook" do
# count
# invocation_order << :example
# expect(invocation_order).to eq([:let!,:example])invocation_order << :example expect(invocation_order).to eq([:example]) expect(other_count).to eq(0) other_count +=1 expect(other_count).to eq(1)end
it "calls the helper method in a before hook again" do
# count
# invocation_order << :example
# expect(invocation_order).to eq([:let!,:example])
invocation_order << :example
expect(invocation_order).to eq([:example,:example])
expect(other_count).to eq(1)
other_count +=1
expect(other_count).to eq(2)
end
end
describe "let test" do
let(:count) { $count += 1 }
# 可以使用count
end
describe "no let test" do
# 不能使用count
end
下面是let!的使用方法
-
spec/helpers/let_bang_spec.rb *
describe "let!" do
count = 0
invocation_order = []let!(:count) do
invocation_order << :let!
count += 1
endit "calls the helper method in a before hook" do
invocation_order << :example
expect(invocation_order).to eq([:let!, :example])
expect(count).to eq(1)
endit "calls the helper method in a before hook again" do
invocation_order << :example
expect(invocation_order).to eq([:let!, :example, :let!, :example])
expect(count).to eq(2)
end
end
5 before用法
http://stackoverflow.com/questions/5974360/rspec-difference-between-let-and-before-block
http://stackoverflow.com/questions/5359558/when-to-use-rspec-let?lq=1
let 和 before(:each)的區(qū)別, let不會(huì)自動(dòng)初始化變量,而before(:each)會(huì)自動(dòng)初始化變量.如果我其中的某一個(gè)測試用力不需要這些變量,依然需要初始化,如初始化變量需要很多時(shí)間,對這個(gè)測試的初始化就是浪費(fèi)的時(shí)間和資源.
before(:each)的用法
-
spec/helpers/before_each_spec.rb *
require "rspec/expectations"
class Thing
def widgets
@widgets ||= []
end
end
describe Thing do
before(:each) do
@thing = Thing.new
end
describe "initialized in before(:each)" do
it "has 0 widgets" do
@thing.should have(0).widgets
end
it "can get accept new widgets" do
@thing.widgets << Object.new
end
it "does not share state across examples" do
@thing.should have(0).widgets
end
it "does not have 1 count" do
@thing.should_not have(1).widgets
end
end
end
before(:all)用法
-
spec/helpers/before_all_spec.rb *
require "rspec/expectations"
class Thing
def widgets
@widgets ||= []
end
end
describe Thing do
before(:all) do
@thing = Thing.new
end
describe "initialized in before(:all)" do
it "has 0 widgets" do
@thing.should have(0).widgets
end
it "can get accept new widgets" do
@thing.widgets << Object.new
end
it "shares state across examples" do
@thing.should have(1).widgets
end
it "should not have 0 widgets" do
@thing.should_not have(0).widgets
end
end
end
6 model 測試
spec/models/widget_spec.rb
describe Widget do
context "test fields" do
before do
@widget = create(:widget)
end
subject{ @widget }
# respond_to 用來判斷屬性有沒有
it { should respond_to(:name) }
it { should respond_to(:email) }
it { should respond_to(:address) }
it { should respond_to(:lat) }
it { should respond_to(:lng) }
it { should be_valid }
# 簡約的寫法
describe "when name is not present" do
before { @widget.name = " " }
it { should_not be_valid }
end
# 繁瑣的寫法
describe "when name is not present" do
before { @widget.name = " " }
# 將it的單行的方式,改寫成多行的方式
it "should not be valid" do
expect(@widget).not_to be_valid
end
end
describe "when name is invalid" do
before { @widget.name = nil }
it { should have(1).errors_on(:name) }
end
describe "when name length > 50 " do
before do
@widget.name = "a"*51
end
it { should_not be_valid }
end
describe "when email is invalid" do
before { @widget.email = nil }
it do
# Email can't be blank, Email is invalid
should have(2).errors_on(:email)
end
end
describe "when email is invalid" do
it "should be invalid" do
# 使用each 循環(huán),遍歷非法的email
addresses = %w[user@foo,com user_at_foo.org example.user@foo.
foo@bar_baz.com foo@bar+baz.com]
addresses.each do |addr|
@widget.email = addr
expect(@widget).not_to be_valid
end
end
end
describe "when email is valid" do
it "should be valid" do
# 使用each 循環(huán),遍歷可用的email
addresses = %w[user@foo.COM A_US-ER@f.b.org
frst.lst@foo.jp a+b@baz.cn]
addresses.each do |addr|
@widget.email = addr
expect(@widget).to be_valid
end
end
end
# ========== 上述驗(yàn)證郵箱的可該寫成如下
describe "when email" do
context "is valid" do
it "should be valid" do
addresses = %w[user@foo.COM A_US-ER@f.b.org
frst.lst@foo.jp a+b@baz.cn]
addresses.each do |addr|
@widget.email = addr
expect(@widget).to be_valid
end
end
end
context "is invalid" do
it "should be invalid" do
addresses = %w[user@foo,com user_at_foo.org example.user@foo.
foo@bar_baz.com foo@bar+baz.com]
addresses.each do |addr|
@widget.email = addr
expect(@widget).not_to be_valid
end
end
end
end
end
context "when initialized" do
# 創(chuàng)建默認(rèn)的共享變量
subject(:widget) { Widget.new(:name => Faker::Name.name,
:email => Faker::Internet.email) }
it "should increment the Relationship count" do
expect do
Widget.create!(:name => "first comment", :email => Faker::Internet.email)
Widget.create!(:name => "second comment", :email => Faker::Internet.email)
end.to change(Widget, :count).by(2) # from(1).to(3)
# https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/expect-change
end
# 第一種寫法
it "is a new widget" do
expect(widget).to be_a_new(Widget)
end
# 第二種寫法
it { should be_a_new(Widget) }
it "is not a new string" do
expect(widget).not_to be_a_new(String)
end
end
context "when saved" do
subject(:widget) { create(:widget) }
it "is not a new widget" do
expect(widget).not_to be_a_new(Widget)
end
it "is not a new string" do
expect(widget).not_to be_a_new(String)
end
end
end
7 controller測試
spec/controllers/widgets_controller_spec.rb
describe WidgetsController do
# show ============
describe "GET #show" do
#? 和控制器動(dòng)作交互的基本 DSL 句法:每個(gè) HTTP 請求方法都對應(yīng)于一個(gè)方法(本例中的方法
#是 get) ,其后跟著動(dòng)作的 Symbol 形式(:show) ,然后是傳入的請求參數(shù)(id: contact) 。
#? 控制器動(dòng)作實(shí)例化的變量可以通過 assigns(:variable_name) 方法獲取。
#? 控制器動(dòng)作的返回結(jié)果可以通過 response 獲取。
it "assigns the required 1 to @1" do
widget = create(:widget)
get :show, id: widget
expect(assigns(:widget)).to eq widget
# http://stackoverflow.com/questions/8616508/what-does-assigns
#
end
it "renders the :show template " do
widget = create(:widget)
get :show, id: widget
expect(response).to render_template :show
end
end
# new ============
describe "GET #new" do
it "assigns a new Widget to @widget" do
get :new
expect(assigns(:widget)).to be_a_new(Widget)
end
it "renders the :new template" do
get :new
expect(response).to render_template :new
end
end
# edit ============
describe "GET #edit" do
it "assigns the request widget to @widget" do
widget = create(:widget)
get :edit, id: widget
expect(assigns(:widget)).to eq widget
end
it "renders the :edit template" do
widget = create(:widget)
get :edit, id: widget
expect(response).to render_template :edit
end
end
# create ============
describe "POST #create" do
context "with invalid attributes" do
# create動(dòng)作, 在符合 REST 架構(gòu)的程序中,這個(gè)動(dòng)作可以響應(yīng) POST 請求。
# create 動(dòng)作和響應(yīng) GET 請求的動(dòng)作最主要的不同點(diǎn)是,不能像 GET 請求那樣只傳入:id 參數(shù),而
# 要傳入 params[:widget] 對應(yīng)的值,這個(gè)值就是用戶可能在表單中輸入的內(nèi)容。
it "does not save the new widget in the database" do
expect{
post :create,
widget: attributes_for(:invalid_widget)
}.to change(Widget, :count).by(0)
end
# expect的另一種寫法
it "does save the new widget in the database again" do
expect do
post :create,
widget: attributes_for(:widget)
end.to change(Widget, :count).by(1)
end
it "re-renders the :new template" do
post :create,
widget: attributes_for(:invalid_widget)
expect(response).to render_template :new
end
end
context "with valid attributes" do
it "does save the new widget in the database" do
expect{
post :create,
widget: attributes_for(:widget)
}.to change(Widget, :count).by(1)
end
it "re-renders the assigns[:widget] template" do
post :create,
widget: attributes_for(:widget)
expect(response).to redirect_to widget_path(assigns[:widget])
end
end
# update ============
describe "PATH #update" do
before :each do
@widget = create(:widget, name: 'lisi', email: 'lisi@126.com')
end
context "valid attribute" do
# 先測試請求
it "located the request @widget " do
patch :update, id: @widget, widget: attributes_for(:widget)
expect(assigns(:widget)).to eq(@widget)
end
# 其次測試上傳的數(shù)據(jù),是否發(fā)生了變化
it "changes @widget`s attributes" do
patch :update, id: @widget,
widget: attributes_for(:widget, name: "lol", email: "lol@126.com")
@widget.reload
expect(@widget.name).to eq("lol")
expect(@widget.email).to eq("lol@126.com")
end
# 最后測試,返回結(jié)果
it "redirect to the updated widget" do
patch :update, id: @widget, widget: attributes_for(:widget)
expect(response).to redirect_to @widget
end
end
context "with invalid attributes" do
it "does not change the contact`s attribues" do
patch :update, id: @widget,
widget: attributes_for(:widget, name: nil, email: "nil@126.com")
@widget.reload
expect(@widget.name).to eq("lisi")
expect(@widget.email).not_to eq("nil@126.com")
end
it "re-renders the edit template" do
patch :update, id: @widget,
widget: attributes_for(:invalid_widget)
expect(response).to render_template :edit
end
end
end
# delete ============
describe "DELETE destroy" do
before :each do
@widget = create(:widget)
end
it "delete the widget" do
expect{
delete :destroy, id: @widget
}.to change(Widget, :count).by(-1)
end
it "redirect to widget#index" do
delete :destroy, id: @widget
expect(response).to redirect_to widgets_path
end
end
end
describe "GET index" do
it "has a 200 status code" do
get :index
expect(response.status).to eq(200)
end
it "renders the index template" do
get :index
expect(response).to render_template("index")
expect(response.body).to eq ""
end
it "renders the widgets/index template" do
get :index
expect(response).to render_template("widgets/index")
expect(response.body).to eq ""
end
it "not renders the 'new' template" do
get :index
expect(response).not_to render_template("new")
end
end
end
8 route測試
首先運(yùn)行
rails generate controller admin/Accounts index
用這個(gè)來創(chuàng)建一個(gè)namespace為admin的account_controller.rb
-
spec/routing/admin_routing_spec.rb*
require "spec_helper"
describe "routes for Widgets" do
it "routes /admin/accounts to the admin/accounts controller" do
expect(get("/admin/accounts")).
to route_to("admin/accounts#index")
end
it "routes /admin/accounts to the admin/accounts controller again" do
expect(get("/admin/accounts")).
to route_to(:controller => "admin/accounts", :action => "index")
end
end
spec/routing/widgets_routing_spec.rb
describe "routes for Widgets" do
it "route to widgets" do
expect(:get => "/widgets").to be_routable
end
it "does not route to widgets/foo/bar" do
expect(:get => "/widgets/foo/bar").not_to be_routable
end
end
*spec/routing/widgets_routing_spec.rb *
it "routes a named route" do
expect(:get => new_widget_path).
to route_to(:controller => "widgets", :action => "new")
end
9 factory_girl 的使用
1.修改Gemfile配置
group :development, :test do
gem 'factory_girl_rails', '4.2.1'
gem 'ffaker', '~> 1.21.0'
gem 'rspec-rails', '2.13.1'
end
并且使用 gem 'jbuilder', '1.5.0'
配置完成之后,執(zhí)行bundle install
2.在 * app/views/widgets/index.json.jbuilder * 文件中
json.widgets @widgets do |widget|
json.id widget.id
json.name widget.name
end
在 * app/views/widgets/show.json.jbuilder*文件中
json.widget do
json.id @widget.id
json.name @widget.name
end
3.在 spec/factories/widget.rb文件中
FactoryGirl.define do
factory :widget do
name { Faker::Name.name }
end
end
4.在* spec/requests/widgets_spec.rb *文件中
describe "Widgets" do
describe "GET /widgets" do
let(:widgets) { FactoryGirl.create_list(:widget, 10) }
let(:url) { "/widgets.json" }
before do
WidgetsController.stub(:index).and_return(widgets)
get(url)
end
describe "return JSON" do
it { MultiJson.decode(response.body)["widgets"].should have_at_most(10).items }
it "should be correct" do
expect(MultiJson.decode(response.body)["widgets"].first["id"]).to eq(widgets.first.id)
expect(MultiJson.decode(response.body)["widgets"].first["name"]).to eq(widgets.first.name)
end
end
end
describe "specify widget" do
let(:widget) { FactoryGirl.create(:widget) }
let(:url) {"/widgets/#{widget.id}.json"}
before { get(url) }
it "should be correct" do
expect(MultiJson.decode(response.body)["widget"]).to include("id")
expect(MultiJson.decode(response.body)["widget"]).to include("name")
end
it "should render the deal in JSON format" do
expect(MultiJson.decode(response.body)["widget"]["id"]).to eq(widget.id)
expect(MultiJson.decode(response.body)["widget"]["name"]).to eq(widget.name)
end
end
end
5.在spec/spec_helper.rb文件中配置如下
每次在測試中,都必須使用FactoryGirl.create(xxx) FactoryGirl.create_list(xxx)
在Factory Girl 3.0 開始, 只要做一個(gè)設(shè)置,Rails就會(huì)變得簡潔,美好
可以加在spec_helper.rb文件Rspec.configure塊中的任何地方
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
然后在測試的代碼中,就能使用比較簡潔的語法create(xxx) create_list(xxx)
還能使用attributes_for(xxx)等
6.Factory生成文件存放的位置
通過Factory Girl生成器生成的文件都會(huì)放在 spec/factories文件夾
中,文件的名字會(huì)試用對應(yīng)模型名字的復(fù)數(shù)形式(所以Contact
模型的預(yù)構(gòu)件文件是spec/factories/contacts.rb)
10 ffaker的使用
faker在用來創(chuàng)建比較真實(shí)的假數(shù)據(jù).
ffaker是faker的重寫,速度比faker塊一些.
修改Gemfile配置
require 'ffaker'
之后執(zhí)行bundle installl給應(yīng)用程序安裝ffaker gem包.
下面是常用的示例.
Faker::Name.name #=> "Christophe Bartell"
Faker::Internet.email #=> "kirsten.greenholt@isher.info"
Faker::Geolocation.lat #=> 38.4685363769531
Faker::Geolocation.lng #=> -87.888795
Faker::Address.street_address #=> "95519 Evans Oval"
Faker::Lorem.sentence #=> "Aut recusandae quam cum omnis aut dolores."
Faker::Lorem.paragraph #=> "Earum et est qui id totam adipisci sint. In qui officia velit veritatis rerum consequuntur. Aut earum eaque velit. Numquam minima autem at."
11 mock的使用
為什么要使用mock?
系統(tǒng)總是很復(fù)雜,不同的模塊功能耦合在一起,A調(diào)用B, B調(diào)用C甚至A.但是我們在測試A
的某個(gè)方法的時(shí)候,應(yīng)該把注意力集中在A這個(gè)方法功能上,而沒有必要把這個(gè)方法中需要的其他方法
(A的或者B,C)都測試一遍,雖然這些其他方法的正確是A的這個(gè)方法正確的保證!B,C的方法應(yīng)該在各自的測試中獨(dú)立進(jìn)行.
如一個(gè)方法,讀取rss,然后解析,生成view
url = "http://forum.rccchina.com/api/posts/meetings.xml"
require 'net/http'
require 'uri'
xml = Net::HTTP.get_print URI.parse(url)
這段代碼核心在后面解析生成view的功能,測試的時(shí)候,完全不需要真的去從forum.rccchina.com上面獲取xml的數(shù)據(jù),覆蓋Net::HTTP.get_print方法即可。
xml = "<meetings>...</meetings>"
Net::HTTP.stub!(:get_print).and_return(xml)
下面是一個(gè)mock的例子
`spec/factories/widget.rb`
FactoryGirl.define do
factory :widget do
name { Faker::Name.name }
email { Faker::Internet.email }
tel { 123456 }
factory :invalid_widget do
name nil
email nil
end
end
end
`spec/first/mock_spec.rb`
require 'spec_helper'
class Hello
def say
"hello world"
end
end
describe Hello do
context "factory girl spec " do
let(:widget) { FactoryGirl.create(:widget) }
subject { widget }
it { should respond_to(:name) }
it { should respond_to(:email) }
it { should respond_to(:tel) }
end
context "mock saying hello " do
before(:each) do
@hello = mock(Hello)
@hello.stub!(:say).and_return("hello world")
@hello.stub!(:sleep).and_return("sleep")
end
subject { @hello }
it { should respond_to(:say) }
it { should respond_to(:sleep) }
end
context "saying hello" do
before(:each) do
@hello = mock(Hello)
@hello.stub!(:say).and_return("hello world")
@hello.stub!(:sleep).and_return("sleep")
end
it "#sleep should return sleep" do
@hello.should_receive(:sleep).and_return("sleep")
answer = @hello.sleep
answer.should match("sleep")
end
it "#say should return hello world" do
@hello.should_receive(:say).and_return("hello world")
answer = @hello.say
answer.should match("hello world")
end
it "#say should not return zzz" do
@hello.should_receive(:say).and_return("hello world")
answer = @hello.say
answer.should_not match("zzz")
end
end
end
從上述的例子中可以看出,FactoryGirl 是根據(jù)模型來模擬真實(shí)的字段屬性.
而mock可以模擬出模型中不存在的字段屬性.mock可以用來虛擬比較復(fù)雜的屬性
12 shared_examples 的使用
shared_examples 解決在測試用需要復(fù)用的代碼
包含shared groups 的文件必須在使用前首先被加載,
一種方法是把所有包含shared examples 的文件放到 spec/support目錄下
并且在spec/spec_helper.rb中導(dǎo)入他們
Dir["./spec/support/**/*.rb"].each { |f| require f }
spec/helpers/shared_examples_spec.rb
shared_examples 'a collection' do
let(:collection) { described_class.new([7,2,4]) }
context 'initialized with 3 items' do
it "says it has three items" do
expect(collection.size).to eq 3
end
end
describe "#include?" do
context 'with an item that is in the collection' do
it "returns true" do
expect(collection).to include(7)
end
end
context "with an item that is not in the collection" do
it "returns false" do
expect(collection).not_to include(9)
end
end
end
end
describe Array do
it_behaves_like 'a collection'
end
describe Set do
it_behaves_like 'a collection'
end
spec/helpers/shared_examples_block_spec.rb
shared_examples 'a collection' do
context 'initialized with 3 items' do
it "says it has three items" do
expect(collection.size).to eq 3
end
end
describe "#include?" do
context 'with an item that is in the collection' do
it "returns true" do
expect(collection).to include(7)
end
end
context "with an item that is not in the collection" do
it "returns false" do
expect(collection).not_to include(9)
end
end
end
end
describe Array do
it_behaves_like 'a collection' do
let(:collection) { Array.new([7,2,4]) }
end
end
describe Set do
it_behaves_like 'a collection' do
let(:collection) { Set.new([7,2,4]) }
end
end
spec/helpers/shared_examples_block_params_spec.rb
require 'set'
shared_examples "a measurable object" do |measurement, measurement_methods|
measurement_methods.each do |measurement_method|
it "should return #{measurement} from ##{measurement_method}" do
subject.send(measurement_method).should == measurement
end
end
end
describe Array, "with 3 items" do
subject { [1,2,3] }
it_should_behave_like "a measurable object", 3, [:size, :length]
end
describe String , "of 6 characters" do
subject { "FooBar" }
it_should_behave_like "a measurable object", 6, [:size, :length]
end
13 注意
1
describe User do
before { @user = User.new(name: "Example User", email: "user@example.com") }
subject { @user }
it { should respond_to(:name) }
it { should respond_to(:email) }
end
ruby代碼中的寫法
@user.respond_to?(:name)
在RSpec中可以寫成
it "should respond to 'name'" do
expect(@user).to respond_to(:name)
end
因?yàn)橹付藄ubject{ @user } 我們還可以寫成單行的形式
it { should respond_to(:name) }
2
require 'spec_helper'
describe Contact do
describe "filter last name by letter" do
context "matching letters" do
end
context "non-matching letters" do
end
end
end
嚴(yán)格上來說describe 和 context 是可以互換的
但是describe 用來表示需要實(shí)現(xiàn)的功能,而context針對該功能不同的情況。
3
2012年6月,Rspec開發(fā)團(tuán)隊(duì)宣布,在v2.11中使用了新句法
來替代傳統(tǒng)的should式句法,如
it "is true when true" do
true.should be_true
end
新句法會(huì)把要測試的值傳遞給 expect() 方法,然后和匹配器比較:
it "is true when true" do
expect(true).to be_true
end
4
describe "Home page" do
before { visit root_path }
it "should have the content 'Sample App'" do
expect(page).to have_content('Sample App')
end
it "should have the base title" do
expect(page).to have_title("Ruby on Rails Tutorial Sample App")
end
it "should not have a custom page title" do
expect(page).not_to have_title('| Home')
end
end
使用最新的rspec特性, 將重復(fù)的東西刪除掉
在代碼中的每一個(gè)用例都出現(xiàn)下面的東西
it "should have the content 'Sample App'" do
同時(shí)還使用了
expect(page).to have_content('Sample App')
二者雖然形式不同,要表達(dá)的意思卻是相同的.而且兩個(gè)用例都引用了page變量
使用it方法的另一種形式,把測試代碼和描述文本合二為一
我們可以告訴Rspec page就是要測試的對象(subject), 這樣就可以避免多次使用page
結(jié)果修改變?yōu)?
subject { page }
describe "Home page" do
before { visit root_path }
it { should have_content('Sample App') }
it { should have_content('Ruby ...')}
it { shoule have_content('| Home') }
end
參考:
http://ibugs.github.com/rspec_test
http://www.relishapp.com/rspec
https://github.com/rspec/rspec-expectations
https://github.com/thoughtbot/factory_girl
http://betterspecs.org/