前言
要了解RSpec,我們首先需要了解什么是行為驅動開發(Behaviour Driven Development,簡稱BDD),BDD是一種融合了可接受性測試驅動計划(Acceptance Test Driven Planning),域驅動設計(Domain Driven Design)以及測試驅動開發(Test Driven Development,簡稱TDD)的敏捷開發模型。RSpec為BDD開發提供TDD支持。
這篇文章遵從TDD思想,但是我們將使用行為(behavior)和樣例(example)來代替測試例(test case)和測試方法(test method)。
介紹
· textual descriptions of examples and groups (rspec-core)
· flexible and customizable reporting
· extensible expectation language (rspec-expectations)
· built-in mocking/stubbing framework (rspec-mocks)
安裝
rails new rspec_tutional –T
加上-T,創建工程時不會添加測試內容,然后修改Gemfile,添加如下內容
group :test, :development do gem ‘rspec’ gem ‘rspec-rails’(兩者版本最好一致) end
然后通過下面的命令創建rspec框架
rails g respec:install
此命令的作用是為Rails程序安裝RSpec框架,使RSpec取代Test::Unit而存在,這條命令會建立’.rspec’文件、’spec’目錄和’spec/spec_helper.rb’文件,他們分別的作用是:
‘.rspec’文件:存放運行rake spec任務時,RSpec需要加載的配置信息。
‘spec’目錄:我們的RSpec測試用例的存放空間,針對mvc,我們可以建立models、views和controllers目錄分別存放模型、視圖和控制器各個層面的測試用例,每一個測試文件以_spec結尾。
‘spec/spec_helper.rb’文件:運行測試用例的RSpec配置文件。每一個以_spec結尾的文件都需要引入該文件,即在文件開頭添加:require ‘spec_helper’代碼。
TDD
describe User do
it "should be in any roles assigned to it" do
user = User.new
user.assign_role("assigned role")
user.should be_in_role("assigned role")
end
it “should NOT be in any roles not assigned to it” do
user = User.new
user.should_not be_in_role(”unassigned role”)
end
end
class User
def in_role?(role)
role == @role
end
def assign_role(role)
@role = role
end
end
Expectations--- Built-in matchers
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)
actual.should equal(expected) # passes if actual.equal?(expected)
actual.should === expected # passes if actual === expected
Identity
actual.should be(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)
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")
Core
上邊是一個比較完整的體現RSpec組織測試用例的模板,當然這里只是為了說明一個_spec文件如何組織測試用例及基本用法,所以我沒有去編寫每一個測試用例的體,並且例子出現的字符串內容不針對於具體的系統,沒有實際意義。下邊依次解釋含義:
require ‘spec_helper’:目的是加載’spec/spec_helper.rb’文件中的RSpec配置,運行時需要。
describe()方法:
我們用describe()方法定義一個測試用例組,describe()方法的參數可以是我們要測試的對象(如例中的People),可以是一個字符串,用來描述該組,describe方法后的字符串所描述的內容可以對應一個用戶故事。
注意describe()方法是可以嵌套的,兩個describe()方法銜接起來可以更細化一個用戶故事,如上邊的里面的describe()方法內就表示:”People have enough money pay for house”。
it()方法:
我們用it()方法定義一個具體的測試用例(在RSpec中,稱一個測試用例為一個example)。其后的字符串為該方法的參數,用來描述一個具體的場景,it方法體就是我們對系統在該場景下的行為的定義。
It()方法和describe()方法銜接起來,可以完整的描述一個系統行為,以上邊的最后的一個測試用例為:”People have enough money pay for house should travel ”。
context()方法:
Context()方法和describe()方法的作用一樣,不同點在於describe傾向於描述我們的測試對象,而context()方法傾向於用字符串描述用戶故事。
before()和after():
這兩個方法很多測試框架都支持,需要說明的是這兩個方法的參數,例子中為符號’:each’,表明對於每一個測試用例,先執行 before()方法中的代碼,用例完成后執行after()方法中的代碼,若參數為’:all’,則表示在所有的測試用例執行之前,先執行 before()方法中的代碼,所有的用例完成后執行after()方法中的代碼。
RSpec還提供around()方法,暫不懂其用法,之后的報告中補上。
幫助方法:
所謂的幫助方法就是把多個測試用例中重復的操作抽出作為一個公用的方法,提高代碼重用度。如例子中的work_hard()方法。
共享行為:
系統的某一個行為是很多場景下都具有的,那么我們可以把它定義為一個共享行為,我們通過share_examples_for()方法 定義共享行為,使用it_behaves_like()方法共享定義過的系統行為,如例子中的share_examples_for “any people”, it_behaves_like “any people”。
pending()方法:
我們確定系統擁有一個行為,但是還沒有具體定義,這時我們可以將該行為使用pending()方法來設置該行為為待定義,其后的字符串參數將在生成的報告中顯示。
pending()方法的另外一種用法就是,當一個測試用例失敗時,我們可以利用pending方法設置其為一個待修復的bug,方法體內包含使用例失敗的代碼。例如最后一個測試用例的內容。
RSpec Story簡介