double 可以讓我們輕易地閃掉準備「協作者」的痛苦。但是有時候,我們還是可能被「協作者」本身的內部邏輯改變整到。比如說,這裡是一個「建議」Suggestion 表單:
require 'rails_helper' RSpec.describe SuggestionsController, type: :controller do describe "POST create" do context "when suggestion is invalid" do it "render new" do post :create, :suggestion => { :title => "", :description => "" } expect(response).to render_template :new end end end end
class Suggestion < ActiveRecord::Base validates :title, presence: true end
class SuggestionsController def create @suggestion = Suggestion.new(suggestion_params) if @suggestion.save redirect_to root_path else render :new end end protected def suggestion_params params.require(:suggestion).permit(:title, :description) end end
如果物件非法的話,要 render new 這個 action。正常來說,這樣的 controller 測試,應該會通過。
但是有時候 controller 程式碼沒有動,但 model 程式碼內部動了,比如說在這個例子,可能多加了新的欄位,或者是新增了其他的驗證方式,導致這個 controller 測試要因為 suggestion 內部本身的邏輯要修改。
這樣真的很討厭。
其實這裡我們根本不應該塞「例子」進去,這樣 suggestion 內部邏輯一旦改變,我們的 controller test 就要改個沒完。我們真正應該要做的是:
所以我們可以把測試改寫成這樣
require 'rails_helper' RSpec.describe SuggestionsController, type: :controller do describe "POST create" do context "when suggestion is invalid" do it "render new" do invalid_suggestion = double(:save => false) allow(Suggestion).to receive(:new).and_return(invalid_suggestion) post :create, :suggestion => { :xxx => "yyy" } expect(response).to render_template :new end end end end
這樣 suggestion 內部驗證再怎麼樣變,都不會影響到這個 controller test。