RSpec-Rails 針對module進行unit test


本文概要:在RSpec describe中載入module必須寫成MyClass.new { include MyModule }

若使用RSpec(v3.2)對Rails進行測試,不免俗要針對各種module進行unit test,尤其是helper、service object、或是各種model及controller當中的concern。不過問題來了,要如何在測試當中載入module?小弟一直以為方式是一樣的,但殊不知,在這裡也卡關許久。

rspec-rails這個gem library針對helper module有提供非常簡便的載入方法,我們的測試會寫成這樣:

require 'rails_helper'

RSpec.describe AppHelper, :type => :helper do
  # 測試內容
end

可以注意到:type => :helper這個敘述,等於直接載入了helper的內容,我們無需再另外考慮其他因素。

不過這裡有個陷阱,也就是並非所有module都可以這樣載入。如果我們有個service object檔案是greeter.rb包含以下內容:

module Greeter
  def hello
    "hello world"
  end
end

假如我們用同樣的邏輯思考,在測試檔案greeter_spec.rb中寫:

require `rails_helper`

RSpec.describe Greeter do
  it { expect(Greeter.new.hello).to eq("hello world") }
end

這樣寫會產生NoMethodError,因為這樣預設的載入方法只能載入class,如果要載入module,必須跟class綁在一起,所以我們要載入有include該module的class(啥?你module只有單獨用嗎?那應該改成叫做class才對吧!)

假如我們有個controller使用該module例如:

class AppController < ApplicationController
  include Greeter
end

那在spec檔案中就可以改寫如下:

require `rails_helper`

RSpec.describe AppController.new { include Greeter } do
  it { expect(AppController.hello).to eq("hello world") }
end

這樣就可以囉!但需要注意兩個地方: 1. 要用AppController.new { include Greeter }2. AppController.hello代表需要用controller來啟動module中的method,而非使用module

說實在,這樣繞道有點遠,本人也還在想有什麼比較簡便的方法來載入module。大家有建議歡迎提供,謝謝。

2009年時就已經存在這個寫法:StackOverflow