最近我寫了一些對象,其中一個方法的行爲有時包含在某些條件下調用另一個方法的方法。爲了測試這個,我一直在嘲笑對象自己調用的方法,因爲它可以更容易地覆蓋代碼中的每個分支,而無需組合爆炸。這通常被認爲是不好的做法。但是,這裏有一個例子幾乎完全反映了我現在正在處理的一段代碼(用CoffeeScript編寫,但這個哲學問題在其他語言中也出現過了)。被測對象的模擬方法
class UserDataFetcher
constructor: (@dataSource) ->
fetchUsernameAsync: ->
# ... snip ... Hits API and raises any errors
fetchUserCommentsAsync: ->
# ... snip ... Hits API and raises any errors
fetchUsernameAndUserCommentsAsync: ->
# ... snip ... Calls each of the above in order and handles errors specially
這很簡單。 fetchUsernameAsync
和fetchUserCommentsAsync
每個與給定的@dataSource
交互以獲取數據。然後我們有fetchUsernameAndUserCommentsAsync
這實質上是一個組合的方法調用其他兩個並以某種方式處理它們;在這個例子中,它可能想重新產生由fetchUsernameAsync
產生的任何錯誤,但是吞下fetchUserCommentsAsync
引發的任何錯誤。
測試前兩種方法的行爲是微不足道的;我嘲笑了他們各自對@dataSource
的調用,並斷言他們以正確的格式返回數據或允許引發任何錯誤。測試最後一種方法的行爲就是我的困境。
它仍然是一個簡單的方法,具有最少的分支邏輯,並通過傳遞消息來委託大部分工作。通常,我會通過嘲笑其「協作者」來測試其行爲,並對某些正在傳遞的消息進行斷言,並以適當的格式返回數據或正確地失敗。但區別在於它只有一個「合作者」,this
。我會嘲笑被測對象的一些方法,這被認爲是不好的做法。
很明顯,解決這個問題的方法是將此方法移到不同的對象;它將是一個只有一個方法和幾乎完全相同的機制的對象,它可以讓我在不違反「不要模擬被測對象」方法規則的情況下嘲笑其協作者。它可能會有一個荒謬的名字,比如UsernameAndCommentsFetcher
,我會從一個小班走到兩個微小的,幾乎微觀的班。小的類很好,但是這個粒度級可能有點矯枉過正,在這種情況下只會滿足「不要模擬被測對象的方法」規則。
這是一個堅實的規則還是有這種情況下,這種情況下,彎曲規則是合理的?
(注:我知道這是類似這個問題,但我認爲這個例子是不夠的不同,值得重新審視:As a "mockist" TDD practitioner, should I mock other methods in the same class as the method under test?)