Website logo

Robert Chang

技術部落格

RSpec - 你一定要知道的 Matchers

今天會開始介紹許多好用的 matcher 也就是配對子,從開始到現在我們都只使用過 eq 這種用法

其實還有很多有趣的 matcher 可以使用!

今天會介紹三種不同的 matcher 但又很相似的,分別是 eq eql be

eq Matcher

eq 是我們最常使用的 matcher,其概念也非常簡單,就是單純的比較 value,而不比較 type !

可以用一些示範來比喻一下!

RSpec.describe "eq matcher" do
  let(:a) { 5.0 }
  let(:b) { 5 }

  it 'only tests for value' do
    expect(a).to eq(5)
    expect(b).to eq(5.0)
    expect(a).to eq(b)
  end
end

這會是一個全部通過的情況!我們也說過 eq 只看值,不看型別。

為什麼會這樣說呢?因為其實在 Ruby 的世界中 5 and 5.0 兩個是屬於不同的類別!

若是在 IRB 中試試看:

> 5.class
> Integer
> 5.0.class
> Float

在 Ruby 的整數和浮點數是不同的類別,自然而然也不會是同一個 type!

eq 會略過型別的比對,專注在值是否吻合!

而一直強調型別,那會根據型別來判斷的 matcher 是哪個呢?

eql Matcher

雖然只差了一個 l 的字母,但在處理的嚴謹度上就完全不相同了!

如果一樣使用剛剛的範例,但改用 eql 來看看會發生什麼事情?

RSpec.describe "eql matcher" do
  let(:a) { 5.0 }
  let(:b) { 5 }

  it 'tests for value and type' do
    expect(a).to eql(5)
    expect(b).to eql(5.0)
    expect(a).to eql(b)
  end
end

沒通過的結果:

screen shot

他會告訴你,55.0 是不相同的東西,測試不通過!

你會想說,這樣有什麼差別啦,現實世界中 5 和 5.0 有什麼不一樣嗎?

但情境如果是在處理精密的匯率或是稅率等等,使用 eq 來做 matcher 是不是會有一點草率呢?

使用 eql 能夠幫你在撰寫方法的時候考慮得更多!也可以想像成嚴格模式~

因為它必須是 相同的 value 以及 相同的類別 才能被認定為相同!

接下來我想介紹更嚴格的一個 matcher,他不只要你是同一個型別,他還要你是同一個物件!

equal Matcher & be Matcher

會放在一起講的原因是 equal 等同於 be,所以接下來我們會一起示範這要怎麼用!

但在放上範例之前,想先提兩個概念:

equality 意思是在確認兩個物件在基本的設計上一樣的!

identity 意思是在確認兩個物件是同一個物件!

為什麼會講這樣的概念呢?因為 equal 就是 identity 的概念,而上面的 eq eql 都像是 equality 的概念!

我們換個類比的方法,假設在一條大街上,我和隔壁的鄰居蓋了一間一模一樣的房子 ( 是真的一模一樣,包含窗框、草皮、房門等等 )

你心裡會說,這兩個房子長得一模一樣欸!但你不會說這是同一個房子,對吧?

就算他們在怎麼像,像到完全看不出來差別,你還是能用地址來做判斷,他們還是兩間房子!

等等示範的 equal 就是在幫你檢查是不是同一個地址的意思!

eq eql 都只是看看照片說,這兩個根本一模一樣嘛~

廢話不多說,我們直接上 Code 吧!

RSpec.describe "equal matcher & be matcher" do
  let(:a) { [7, 7, 7]}
  let(:b) { [7, 7, 7]}
  let(:c) { a }

  it "test for object identity" do
    expect(a).to eq(b)
    expect(a).to eql(b)

    expect(a).to equal(c)
    expect(a).not_to equal(b)
  end
end

上面是一個會全部通過的測試!

這邊的 c 變數,指向 a 變數,這代表著什麼?

我把我家的地址填得和你家地址一樣,這兩個會指向在同一個地方的物件!

ab 在值以及型別上來看,都一模一樣,但他們在記憶體中的地址卻不相同,我們可以故意讓測試壞掉來看看 OutPut 是什麼?

我們讓 a equal b 來試試看!

錯誤的提示:

screen shot

可以看到兩個在 Array 的記憶體位置是不相同的 ( 一個是 2800, 一個是 2820 ),這就像上面舉例有關房子的案例一樣,雖然長得一樣,但終究是兩個個體!

下面的提示也有告訴你,這是在比較物件的 identity

剛剛範例上都使用 equal,但其實你也可以用 be 達到一樣的效果

結語

重新複習一下三者的不同之處!

eq:單純比較值,不在意型別

eql:比較值以及型別

equal 以及 be:比較值,型別,記憶體位置(是否為同一個物件)

希望以後大家在使用的時候,可以根據要測試的嚴謹程度來決定要使用哪一個 matcher

這三個都是非常基礎的 matcher 但卻常常不知道錯在哪,希望這篇文章可以幫助到你

上一篇文章RSpec - 分享範例,整理範例

下一篇文章RSpec - 更多的 Matchers ( 上 )