test code 亂 → 越難修改 → 花更多時間在寫新 test code → 舊測試碼開始沒辦法過 → 放棄測試 → 容易出錯
TDD(Test Driven Developement) 的三大法則
👉 步驟 1:在撰寫一個單元測試時,不可撰寫任何產品程式
👉 步驟 2:只撰寫剛好無法通過的單元測試,不能編譯也算無法通過
👉 步驟 3:只撰寫剛好能通過當前測試失敗的程式
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);
}
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);
}
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);
}
Fast(快速): Test 的執行速度越快越好,但可讀性最重要!
Independent(獨立): 測試程式不應該互相依賴,這樣子一個 unit test fail 了才不用還要去檢查其他的 unit test
Repeatable(可重複性): 測試程式應該可以在任何環境中執行
Self-Validating(自我驗證): 測試程式應該輸出Boolean值,不管測試成功或失敗,都不應該還要自己在那邊看 log
Timely(及時地): 撰寫測試程式要及時,單元測試要恰好在使其通過的產品程式之前撰寫(TDD概念)。
class 的結構 → stepdown rule
public class dog(){
public static variable
private static variable
public variable
private variable
public function
private function
}
像是函式一樣
用 25 個內的單字描述他,不用 if else or but 等詞彙
Responsibility is one reason to change
A class should have only one reason to change.
// Modem
interface Modem
{
// 撥號
public function dial($pno);
// 掛斷
public function hangup();
// 發送資料
public function send($c);
// 接收資料
public function recv();
}
interface Connection
{
// 撥號
public function dial($pno);
// 掛斷
public function hangup();
}
interface DataChannel
{
// 發送資料
public function send($c);
// 接收資料
public function recv();
}
class 只有少量的實體變數,盡量讓所有 function 都用到這些變數,如果發現凝聚性低,就要考慮拆解 class
將 class 大函式分解成小函式 → 靠實體變數避免參數傳遞 → 越來越多實體變數 →少數函式用到一個實體變數 → 他們應該自成一個 class
Software entities (class, modules, functions, etc.) should be open for extension, but closed for modification.
一個軟體製品在面對擴展時是開放的,且擴充時不應修改到原有的程式。
Ex: Linux Kernel, Chrome extension
怎麼不改 code ,又改變行為?
善用 abstract interface!
public function getData()
{
// 下載資料
// 載入 XML
// 解析 XML
return data;
}
public function getData()
{
// 下載資料
if(XML){
// 載入 XML
// 解析 XML
}
else if(JSON){
// 載入 JSON
// 解析 JSON
}
return data;
}
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;
}
}