## 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}]"}