為何要使用 Mock
在撰寫測試時,會有一些實際上不希望執行的處理,例如寄信、快取讀寫或呼叫外部 API。
把這類處理替換為「假裝的替身」的作法就稱為 mock。
Mock 的好處包含:
- 測試速度快:不執行外部服務或耗時處理,測試很快完成
- 測試穩定:不受外部服務狀態影響,結果始終一致
- 測試範圍清晰:可以只驗證單一類別或方法
Laravel 已提供可立即使用的 mock 輔助函式,涵蓋事件、Job、Facade 等。
其內部使用 Mockery,不需複雜設定即可使用。
Mock 物件
若要 mock 透過服務容器注入的物件,可將 mock 實例綁定到容器。
如此一來,容器會用 mock 實例取代原本要建立的物件。
mock() 方法
Laravel 測試基底類別提供的 mock() 方法可以更精簡地寫出同樣結果。
partialMock() 方法
若只想 mock 物件的部分方法,可用 partialMock()。
未 mock 的方法會照常執行。
spy() 方法
Spy 類似 mock,但差在執行程式碼後才驗證互動。
Mock 是事先設定「這個方法應該被呼叫」;spy 則是事後檢查「這個方法是否有被呼叫」。
Facade 的 Mock
Facade 與一般靜態方法呼叫不同,是可以 mock 的。
在具備依賴注入等同可測試性的同時,可用更簡潔的語法書寫。
以使用快取的控制器為例:
要 mock Cache Facade 的 get 方法,使用 expects():
請不要 mock Request Facade。改為在 get 或 post 等 HTTP 測試方法上傳入輸入資料。同樣地,別 mock Config Facade,改在測試中直接呼叫 Config::set()。
Facade Spy
要以 spy 監控 Facade,可呼叫對應 Facade 的 spy() 方法。
適合在程式碼執行後才驗證互動的情境。
時間操作
在測試中驗證與時間相依的邏輯時,能改變 now() 或 Carbon::now() 所回傳的時間會很方便。
Laravel 的 feature test 基底類別提供了操作時間的輔助方法。
travel() — 移動時間
用閉包做時間移動
傳入閉包給時間移動方法時,會在指定時間停止時間並執行閉包,完成後恢復到原本時間。
freezeTime() — 停止時間
freezeTime() 會凍結目前時間。freezeSecond() 會凍結在目前秒的起點。
實用範例:閒置討論串的鎖定
時間操作非常適合測試如「一段時間無操作即鎖定討論串」這類功能。
travel() 等時間操作方法只能在 feature 測試(繼承 Tests\TestCase 的類別)中使用,PHPUnit 的基底 TestCase 中無法使用。
方法一覽
Mock 相關
時間操作相關