單元測試法則

單元測試法則

What should we test?


Incoming & Outgoing Messages

上圖表示一個物件是如何被測試的。
測試物件的時候,你可以發現受測物件會接收發送訊息:
  • Incoming Messages 表示呼叫受測物件的訊息
  • Outgoing Messages 表示受測物件傳遞給其依賴物件的訊息
訊息可以被傳進物件,也會被物件傳遞出去(如上圖你可以看見有訊息進入物件,也有訊息從物件出去)。
進行測試時,你只能對物件傳遞訊息,沒有辦法看見物件的內部。這就是為什麼要
測試介面,不要測試實作。 (testing the interface, and NOT the implementation.)

測試介面讓我們可以隨意切換實作類別,並且不破壞測試程式。


Query & Command Messages

除了 Incoming & Outgoing Messages 以外,訊息還分為 Query 與 Command 兩種:
Query Message: messages return data without changing anything.
  • 只返回 Data,不做修改任何物件屬性的訊息
  • 不會替應用程式帶來副作用。
Command Message: messages modify data without returning any data.
  • 只修改物件屬性,但不返回任何 Data 訊息
  • 一定會有副作用。
合併的 Command 與 Query 訊息:
這種訊息除了修改資料與回傳資料外,還可能有隱藏的副作用。
(如新增一筆 user 資料並返回新的 user ID,但是 DB 內的 ID 自動 +1)
在商業邏輯一定要使用合併訊息時,一定要確保這些訊息不能含有意料外的副作用。

Test Double


為什麼要 Test Double?

1. 隔離依賴:

單元測試目的是要測試受測物件的行為是否符合預期,如果連受測物件的依賴物件也一起進行測試,那就叫做整合測試了。
因此單元測試需要隔離依賴。

2. 要求快速:

單元測試的時間應該非常短,才可以向開發者快速反饋信息

進行重構時,一點點修改就要立刻執行測試,確保功能沒有被改壞。如果每次執行測試,受測物件將訊息遞給依賴物件處理 15 秒才回傳值。就會大幅減緩開發速度。
使用測試替身隔離依賴物件,避免訊息在 N 多個物件之間來回傳遞。(參考上圖)即可加快單元測試的速度。
測試替身用途
Stub 用來測試 Outgoing Query Message

Stub 代替的訊息不會對整個應用程式帶來副作用,所以訊息如何被傳遞並不那麼重要。
Mock 用來測試 Outgoing Command Message


Mock 代替的訊息會對應用程式有副作用。所以一定要用 Mock 確保受測程式有沒有正確將訊息傳遞出去。

參考資源

留言

這個網誌中的熱門文章

Git Commit Message 這樣寫會更好,替專案引入規範與範例

Gitlab 合併請求 Merge Request 是什麼?

再談物件導向設計原則: 單一職責原則,定義、解析與實踐