使用 double ( mock objects )
Four-Phase Test 是一種常見的測試 Pattern。幾乎也是一般人在寫測試的手法,依序為:
- Setup (準備測試資料)
- Exercie (實際執行測試)
- Verification (驗證測試結果)
- Teardown (拆解測試)
但是通常我們在一般寫測試或者是 TDD 時,常常會遇到一些狀況,導致 Setup 階段時,資料「難以被準備」。通常是有以下幾種狀況:
對象物件當中的「協作者」還沒被誕生,比如說都還沒寫到那個 class 或者是 method
對象物件當中的「協作者」是「系統外部物件」,如: API 回傳內容
要準備的資料、相依性過於複雜,要生超多物件才能測試
執行這個測試,呼叫到「吃效能很重」的測試,導致測試運行緩慢
使用替身
但我們的首要要務,其實是要測我們內部的程式的邏輯,不是要測「外部邏輯」的狀況。所以我們可以使用 mock objects,在 RSpec 裡面叫做 double(替身)。
在 Setup 階段使用「替身」的資料,直接進行測試。
舉例來說,我這裡有一個學生計算器
class StudentsCalculator
def initialize(course)
@course = course
end
def students_count
@course.students_count
end
end
我還沒想好 course.students_count 要怎樣設計(這在 TDD 中很常見),但是我知道在 StudentsCalculator 中的邏輯,吃的就是將來 course 提供的 students_count,而且「我現在就想要驗證這件事」。所以我可以假造一個 course 的替身,讓這段測試可以通過。
require "rails_helper"
RSpec.describe StudentsCalculator do
describe "#students_count" do
it "returns students count" do
course = double(:students_count => 5 )
student_calculator = StudentsCalculator.new(course)
expect(student_calculator.students_count).to eq(5)
end
end
end