RSpec-Rails當中自訂methods及helpers

2015-03-20 by Adler Hsieh


在RSpec當中,常常會有些瑣碎的東西需要重複輸入,尤其是unit test,如果能夠包成helper methods,在不同檔案間重複利用,是再好不過的事情。以下提供兩個簡便的方法,可以撰寫專門給RSpec使用的methods,不會被Rails app本身觸發到。

1. 定義為Module

最快也最簡便的方法,就是在rails_helper.rbspec_helper.rb裡面定義這些methods,這樣就不用在每一個RSpec檔案當中重新載入(畢竟每次都要require 'rails_helper'就已經夠煩了)。

例如要測試model之間的關係,我們會在測試當中這樣寫:

require 'rails_helper'

RSpe.describe User, :type => :model do
  it "has_many posts" do
    association = User.reflect_on_association(:post)
    expect(association.macro).to eq(:has_many)
  end
end

當然,只要稍微複雜一點的網站或應用程式,這樣的敘述就會變得非常冗長。假如我們在一個model當中寫了20個這樣的測試,其實對可讀性來說非常沒有幫助。這時,可以把這個method包含到helper中,寫成這樣:

module CustomHelpers
  def expect_relation(model, relation, target)
    association = model.reflect_on_association(target)
    expect(association.macro).to eq(relation)
  end
end

包好之後,再重新調整原本的寫法:

RSpe.describe User, :type => :model do
  it { expect_relation(User, :has_many, :posts)}
end

原本長得要命的兩句話,縮減成簡易又好懂的一句話,這樣就算連續測試10個以上的model relation,code也會乾淨簡潔。

要將helpers納入測試當中,要進入rails_helper.rbspec_helper.rb當中添加,筆者個人比較傾向於前者。接著在最前面幾行加上:

require './spec/custom_helpers'
# 檔名端看如何命名,個人會命名為cusom_helpers.rb

接著在下方的RSpec設定當中添加:

RSpec.configure do |config|
  config.include CsutomHelpers
  # 僅添加此行即可
end

就可以順利在測試中使用該module內包含的methods。

當然,這個方法在官方文件上也有非常詳細的說明。

2. 定義為shared_context

如果用module的方式,那每一個測試都會自動載入該module。假如我們不希望每次都載入該module呢?這時就可以使用shared_context來指定要使用的helpers,sharedcontext的方法稍嫌囉嗦,但如果有特定method只希望其中幾個測試可以使用,那包在sharedcontext當中可以較為精確。

首先在spec資料夾底下開一個contexts資料夾,裡面建立一個helpers.rb檔案。

RSpec.shared_context "custom_helpers" do
  def my_helpers
    # ...
  end
end

定義完成以後,shared_context運作的方式是需要在每個測試當中將context指定納入,才會可以使用,以確保只有在需要用的時候再呼叫這些methods。以剛剛的User model為例,寫法變成:

require './spec/contexts/custom_helpers'

RSpe.describe User, :type => :model do
  include_context "custom_helpers"
  # 開始用helper寫code
end

除了讀取檔案之外,也要特別指定include_context才行。如果require檔案嫌麻煩,也可以整理到rails_helper檔案當中,這樣就不需要每次都特別require進來。

官方文件也有詳細說明Shared Context要如何使用。