IT 邦鐵人賽 Day10 - RSpec 基本語法

前面介紹了 RSpec 的規格與測試,讓大家都能明白 TDD 的測試流程,紅燈、綠燈、優化與重構。接下來,我們會花好幾篇來介紹 RSpec 的 語法。

今天我們先來個簡單的,也是前面看過的基本語法:

describe method

RSpec.describe 主要是用來建立一個 example group,在這一個 example group 裡底下會有許多小 example 來進行測試。

RSpec.describe 後面接的,可以是這一個 example group 的主要目標的描述:

1
2
3
RSpec.describe "Quality Examination" do
(略)
end

也可以是主要進行的測試功能、類別等、像是前面提到的:

1
2
3
RSpec.describe MobileWallet do
(略)
end

在這裡,就是以 MobileWallet 這個類別為測試目標。

然後再接 do end 的 block。

因為 Ruby 的 method 慣例是可以省略括號的,所以本來應該是這樣:

1
2
RSpec.describe("Quality Examination")
RSpec.describe(MobileWallet)

it method

it 最主要的功能是讓你的測試項目辨識度大幅提升的好幫手,所以我們在寫 it 時,盡量言簡意賅,一句簡短的話就能把你要做的事情描述出來。

在剛剛提到的 describe 會建立一個 example group,而在這個 group 裡,則含有一個以上的 example。這些 examples 就是由 it 所構成:

1
2
3
4
5
6
7
8
9
10
RSpec.describe "example group" do
it "example_one" do
end

it "example_two" do
end

it "example_three" do
end
end

執行 rspec 後:

透過 it 的方法,可以很清楚的知道,每一個 example 是在做什麼,跑測試結果時,就能一看就知道是誰有過誰沒過,讓整體的可讀性上升。

it 後面打上 example 的描述後,加上一個 do end 的 block,然後在這個 block 裡,就是要打上測試用的 code:

1
2
3
4
5
it "軟體錢包原本有50元,扣款10元後,錢包顯示40元" do
wallet = MobileWallet.new(50)
wallet.cost 10
expect(wallet.total).to be 40
end

expect method

expect 後面帶入受測項目,可以是物件(arr):

1
2
3
4
5
6
RSpec.describe "The length" do
it "should be 7" do
arr = [1, 2, 3, 4, 5, 6, 7].size
expect(arr).to be (7)
end
end

也可以是方法(two):

1
2
3
4
5
6
7
8
def two
1 + 1
end
RSpec.describe ".two_method" do
it "should be 2" do
expect(two).to be (2)
end
end

也可以是物件屬性:

1
2
3
4
5
6
7
8
RSpec.describe MobileWallet do
describe "扣款功能" do
it "軟體錢包原本有50元,扣款10元後,錢包顯示40元" do
wallet = MobileWallet.new(50)
wallet.cost 10
expect(wallet.total).to be 40
end
end

也可以是邏輯運算:

1
2
3
4
5
RSpec.describe "cal" do
it "should be even" do
expect((1 + (1 * 3) ** 2) % 2 ).to be (0)
end
end

這些引數帶入 expect 後,expect 會進行運算,並回傳一個物件,這個物件則包含 @target 這個實體變數,而這個實體變數本身,帶有一些實體方法,像是 to, not_to。

to method

to 是 expect 產出的物件內包含的實體方法,用來承接 matcher method,讓expect 跟 matcher 可以互相比較。

另外還有一個叫 not_to,從字面上的意思就可以知道是 to 的反義。

matcher method

matcher method 是負責配對、比較 expect method 所生之物件與 matcher method 所生之物件是否一致。
我們前幾天測試用的 be 就是其中一個 matcher method,另外還有 eq 與 eql,三者在使用上有不同的差異。

依照嚴謹程度來區分:eq < eql < be。

eq:只要值一樣就好。
eql:值與型別都要一樣。
be / equal:不止值與型別,連記憶體位置都要一樣。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
RSpec.describe "same or different" do
let(:a) { 1234 }
let(:b) { 1234.0 }

let(:c) { [1234] }
let(:f) { [1234.0] }

it "should be the same" do
expect(a).to eq(b)
expect(a).to eql(b)

expect(c).to eq(f)
expect(c).to eql(f)
expect(c).to equal(f)
end
end

之後我們會提到 let method,先稍微知道一下,let 的小括號為變數,大括號為變數的值。

在這個測試第二個跟第四、五個測試會失敗。

第一個: eq 只在乎「值」,所以即便 a 是 integer,b 是 float,也沒關係。
第二個:但因為 eql 會比較型態,所以上面說的沒關係就有關係了,因此這裡就無法通過。
第三個:如第一個所述。
第四個:如第二個所述。
第五個:equal 還會在意記憶體位置是不是一樣,所以執行下去跑出的錯誤。

也把兩個記憶體位置表明出來,由此可知,equal 真的很挑惕(誤),所以 equal / be 比起外在,他也在意內在。

小結

今天介紹了前面測試用到的基本語法,接下來會再介紹其他好用的語法給大家。