5-5 Mocking V.S. Spying

Mocking

在這個例子裡面,我們用了 mock 手法,確認 show 這個 action,真的有去呼叫 Suggestion.find

  • allow(Suggestion).to receive(:find).and_return(suggestion)
  • expect(Suggestion).to receive(:find)
describe "GET show" do
  it "assigns @course and render show" do
    suggestion = double(:to_param => "123" )
    allow(Suggestion).to receive(:find).and_return(suggestion)
    expect(Suggestion).to receive(:find)

    get :show, :id => suggestion.to_param

    expect(response).to render_template :show
    expect(assigns[:suggestion]).to eq(suggestion)
  end
end
class SuggestionController

  def show
    @suggestion = Suggestion.find(params[:id])
  end
end

劣勢:順序「反直覺」

但是其實這樣的寫法,對於我們之前提到的 Four-Phase Test:

  • Setup (準備測試資料)
  • Exercie (實際執行測試)
  • Verification (驗證測試結果)
  • Teardown (拆解測試)

有點相違背了。

我們先做了 Verification (expect)再做 Exercise ( get :show) 。

劣勢:before 階段,expect 如果不如預期,後面測試全死

而且在拆解階段,我們會將這段測試重寫成這樣

describe "GET show" do
  before do
    @suggestion = double(:to_param => "123" )
    allow(Suggestion).to receive(:find).and_return(@suggestion)
    expect(Suggestion).to receive(:find)
    get :show, :id => @suggestion.to_param
  end

  it { expect(response).to render_template :show }
  it { expect(assigns[:suggestion]).to eq(@suggestion)}
end

Spying

我們可以改用 Spy 手法,將測試改成這樣。(RSpec 使用 have_received 去驗證)

describe "GET show" do
  before do
    @suggestion = double(:to_param => "123" )
    allow(Suggestion).to receive(:find).with(@suggestion.to_param).and_return(@suggestion)
    get :show, :id => @suggestion.to_param
  end

  it { expect(response).to render_template :show }
  it "should find suggestion and assign suggestion" do
     expect(Suggestion).to have_received(:find).with(@suggestion.to_param)
     expect(assigns[:suggestion]).to eq(@suggestion)
  end
end

Four Phase 順序不但正確,而且是在 Exercise 後,才做 Verification。

results matching ""

    No results matching ""