## CH9 Unit Test --- ### 測試程式跟產品程式一樣重要 test code 亂 → 越難修改 → 花更多時間在寫新 test code → 舊測試碼開始沒辦法過 → 放棄測試 → 容易出錯 --- TDD(Test Driven Developement) 的三大法則 👉 步驟 1:在撰寫一個單元測試時,不可撰寫任何產品程式 👉 步驟 2:只撰寫剛好無法通過的單元測試,不能編譯也算無法通過 👉 步驟 3:只撰寫剛好能通過當前測試失敗的程式 ```c int Add(int firstNumber, int secondNumber){ return firstNumber + secondNumber; } void AddTest(){ int firstNumber = 1; int secondNumber = 2; int expected = 3; int actual = Add(firstNumber, secondNumber); Assert.AreEqual(expected, actual); } ``` --- - 一個函式只能做一件事 - Unit Test 也是一種函式 - 讓單元測試只包含一個概念 → 減少 assert ---- ```cpp void CalTest(){ int firstNumber = 1; int secondNumber = 2; int expected = 3; int actual = Add(firstNumber, secondNumber); Assert.AreEqual(expected, actual); firstNumber = 3; secondNumber = 2; expected = 1; int actual = Sub(firstNumber, secondNumber); Assert.AreEqual(expected, actual); } ``` ---- ```cpp void AddTest(){ int firstNumber = 1; int secondNumber = 2; int expected = 3; int actual = Add(firstNumber, secondNumber); Assert.AreEqual(expected, actual); } void SubTest(){ int firstNumber = 3; int secondNumber = 2; int expected = 1; int actual = Sub(firstNumber, secondNumber); Assert.AreEqual(expected, actual); } ``` --- ## F.I.R.S.T Fast(快速): Test 的執行速度越快越好,但可讀性最重要! Independent(獨立): 測試程式不應該互相依賴,這樣子一個 unit test fail 了才不用還要去檢查其他的 unit test Repeatable(可重複性): 測試程式應該可以在任何環境中執行 ---- Self-Validating(自我驗證): 測試程式應該輸出**Boolean**值,不管測試成功或失敗,都不應該還要自己在那邊看 log Timely(及時地): 撰寫測試程式要及時,單元測試要恰好在使其通過的產品程式之前撰寫(TDD概念)。 --- ## CH10 Class ---- class 的結構 → `stepdown rule` ```java public class dog(){ public static variable private static variable public variable private variable public function private function } ``` --- ## 簡短有力 像是函式一樣 用 25 個內的單字描述他,不用 if else or but 等詞彙 - 每個 class 有單一功能,且該功能應該由這個 class 完全封裝起來。 - 與其他少數幾個 class 合作來完成系統要求的行為 --- ## 單一職責原則 ### (Single Responsibility Principle, SRP) Responsibility is *one reason to change* > A class should have only one reason to change. ---- ```clike // Modem interface Modem { // 撥號 public function dial($pno); // 掛斷 public function hangup(); // 發送資料 public function send($c); // 接收資料 public function recv(); } ``` ---- ```clike interface Connection { // 撥號 public function dial($pno); // 掛斷 public function hangup(); } interface DataChannel { // 發送資料 public function send($c); // 接收資料 public function recv(); } ``` ---- ## 凝聚性 (cohesion) class 只有少量的實體變數,盡量讓所有 function 都用到這些變數,如果發現凝聚性低,就要考慮拆解 class ---- 將 class 大函式分解成小函式 → 靠實體變數避免參數傳遞 → 越來越多實體變數 →少數函式用到一個實體變數 → 他們應該自成一個 class ---- ### 優點 - 可讀性與可維護性提升 單一類別的複雜度降低,因為要實現的職責都很清晰明確的定義,這將大幅提升可讀性與可維護性 - More rubust 如果有做好 SRP ,那修改只會對同一個介面或類別有影響,這對擴展性和維護性都有很大的幫助。 --- ## 開放封閉原則 ### (The Open/Closed Principle, OCP) >Software entities (class, modules, functions, etc.) should be open for extension, but closed for modification. 一個軟體製品在面對擴展時是開放的,且擴充時不應修改到原有的程式。 Ex: Linux Kernel, Chrome extension ---- 怎麼不改 code ,又改變行為? 善用 abstract interface! ---- ```clike public function getData() { // 下載資料 // 載入 XML // 解析 XML return data; } ``` ---- ```clike public function getData() { // 下載資料 if(XML){ // 載入 XML // 解析 XML } else if(JSON){ // 載入 JSON // 解析 JSON } return data; } ``` ---- ```cpp abstract class DataResource { public function getData() { // 下載資料 // ... $content = curl_exec($ch); $data = $this->parse($content); return $data; } abstract protected function parse($content); } class XmlResource extends DataResource { protected function parse($content) { // 載入 XML // 解析 XML return $data; } } class JsonResource extends DataResource { protected function parse($content) { // 解析 JSON $data = json_decode($content); // ... return $data; } } ``` ```cpp ``` --- ref https://ithelp.ithome.com.tw/articles/10192105 https://ithelp.ithome.com.tw/articles/10191955
{"metaMigratedAt":"2023-06-18T00:39:06.211Z","metaMigratedFrom":"YAML","title":"Clean code","breaks":true,"description":"View the slide with \"Slide Mode\".","slideOptions":"{\"theme\":\"league\",\"transition\":\"fade\"}","contributors":"[{\"id\":\"56dc1b54-fff4-4cc9-81d2-126cb50465ea\",\"add\":6534,\"del\":2013}]"}
    237 views