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。