🎯 什麼情境該想到我

當你「只是想換掉方法裡的某一個呼叫——它會帶來討厭的副作用,或你想感知被傳進去的值」的時候。

⚙️ 怎麼用(步驟)

適用情境(p.275):「許多時候,在測試時遇到的依賴問題都是相當局部的。比如我們可能會遇到一個想要替換掉的方法呼叫。於是若能解開對那個方法的依賴的話,就能夠防止測試帶來古怪的副作用,或可以感知被傳給該呼叫的值。」

核心做法(p.275):「有一個選擇是,將該呼叫提取到一個新方法中,並用一個測試子類來覆蓋它。這一手法也被稱為提取並重寫呼叫。」提取之後,「一旦有了我們自己的 formStyles 方法,便可以通過重寫它來解開依賴了」;因為回傳值和正在測試的東西無關,就可以直接讓重寫版本回傳一個空列表;如果測試需要各種各樣的值,也可以通過修改這個方法來配置(p.276)。

步驟(p.276)

  1. 確定你想要提取的呼叫。找出它所呼叫的方法宣告,複製其方法簽名以便實施簽名保持(249頁)。
  2. 在當前類別上建立一個新方法,用剛剛複製的方法簽名來武裝它。
  3. 把對目標方法的呼叫複製到新方法中,然後在原來的地方改呼叫這個新方法。

書中補充:「如果手頭有自動重構工具,則該手法實施起來簡直太容易了。你只需使用方法提取來對目標方法進行提取即可。然而如果沒有重構工具,則可以考慮如下步驟,遵循它們可以讓你在即使沒有測試的情況下也能安全地完成提取。」(p.276)

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 書中最推薦的使用場合:「提取並重寫呼叫是個非常有用的重構手法,我經常會用到它。如果你的目的是解開對全域變數和靜態方法的依賴,它是個理想的選擇。」(p.276)
  • 呼叫點太多就別用:「一般來說,如果對於同一個全域對象沒有太多位於不同地點的呼叫的話,我傾向於採用該手法;否則,我往往會採用以獲取方法替換全域引用的辦法。」(p.276)跨多個方法多個類別的情況,書中在 封裝全域引用 一節說「使用封裝全域引用就要乾淨一些了」(p.271)。
  • 代價是要開一個測試子類:這條手法靠子類化並重寫該方法來換掉行為(p.275),所以被提取出來的方法必須是可被覆寫的。
  • 整章共通的誠實取捨:這些技術是要在沒有測試的情況下使用的,「其目的是為了將測試安置到位」;「這些技術並不能立竿見影地讓設計變得更好」(p.258)。書中也提醒運用前先讀第 23 章,並且「錯誤仍可能發生,因此你應該小心行事」(p.258)。
  • 與《重構》的差別:它會用到方法提取(見 提煉函式),但兩者目的不同——書中註明本章手法「在步驟上有所不同,我將之適當剪裁以使得它們能夠被安全地用在沒有測試的情況下」(p.258);這裡提取出方法只是為了造出一個能被測試子類覆寫的接縫。

🔗 相關工具