Node.js 使用 Sinon 進行測試
使用隔離框架測試 - 一部曲
前言
如果我們要測試的物件或者是函式依賴於另外一個我們無法控制(或尚未實作)的物件,而這個相依的物件可能是連資料庫,或者是第三方的套件;因為是外部的相依物件,我們並沒有辦法自行決定其回傳值,以及控制其行為,這個時候,我們要透過所謂的 Test Double 方法來進行模擬測試。
手刻模擬物件的問題
想像一下,你有一個函式要把紀錄寫進資料庫,所以你需要自己寫一個假的資料庫模擬物件,或是花時間撰寫 Stub 物件來進行單元測試。
為解決單純因要測試而多做的工作,所以我們可以透過優雅的解決方案:隔離框架,在執行期動態地建立 Stub 物件或 Mock 物件
Test Double
甚麼是 Test Double?Test Double 為測試替身的統稱,一般大家可能在如何撰寫測試碼相關的文章看過以下名詞:Dummy、Fake、Stub、Mock 與 Spy ,以上它們都算 Test Double。
在這篇文章,我們先討論 Spy 跟 Stub 這兩個比較入門級的東西,並且配合使用 Node.js 常用的測試套件:Sinon。
隔離框架的重要性
一個好的隔離框架,是可以幫助寫程式的 API,我們透過這個 API 來幫助我們建立測試的假物件,比起我們慢慢自己寫假物件來得容易多,並且在測試碼方面也好維護。
分離測試的重要性
為什麼需要進行分離測試?相信包括我在內,一開始寫測試碼寫得很快,但是一旦遇到相依性,例如某個商業邏輯要透過撈取資料庫的資料,經過運算後回傳結果,但是中間過要跟資料庫做溝通,所以我們要進行該商業邏輯測試的時候,我們發現我們不單單只是測試商業邏輯,也會同時測到資料庫的運作是否正確,要單獨測試這個邏輯,已是件不可能的事。
要記得單元測試必須與外部環境、類別、資源、服務獨立,而不能直接相依。
為了避免發生因相依性而導致設計與測試上的問題,所以我們要想辦法將有相依性的商業邏輯執行隔離測試。
Stubs
Stub 是一個模擬回傳固定值的實作。
意思是我在測試一段可能牽涉到多個不同類別的邏輯時,為了隔離其他類別的影響性,我們利用 Stub 方法把一個函式覆蓋過去,固定回傳一個固定結果,這樣我們就可以在測試時將相依性問題作解耦。
例如,我們想要把執行 func.logs() 中的做替換,所以我們透過 sinon 的 stub console.warn 物件,改替換為 console.log:
在這邊可以仔細看到,本來的 log 記錄被取代掉了,從 console.log was called again 被改為 Message from stub ,我們達到了 stub 一個函式的方法。
Spy
對 function call 蒐集資訊,便於對測試結果做驗證。
Spy 的工作類似 Stub,但是在 Spy 中,我們會真實執行被測試的函式,監聽並記錄其被呼叫的成員次數。透過這樣的測試方法,我們用以確保物件互動是正確的,例如檢查 console.log 應該只會被呼叫一次。
呼叫 spy.restore() 的原因類似 destory 這個 spy 的資料內容,使之初始化到一開始的狀態。如果不消除, called 的次數會累加,進而導致測試失敗。
Spy 是三者最簡單的部份,並且前面提到的 Stub 以及 Mock 方法皆是建構於 Spy 之上的。
結論
篇幅很短,只是簡單介紹隔離框架的出現原因以及基本應用,隔離框架解決了我們要自行手刻的麻煩,我們應該去多多了解這樣的框架,幫助測試工作,但在實作測試碼上要注意的是:盡量選擇測試回傳值或系統狀態改變的測試,這兩種測試可以減少對程式碼內部細部運作的假設。後面會持續介紹 Sinon 的用法以及更多的測試知識。