第四輪將分離這些test code。
U步驟:檢視test code,可了解做的是針對innerProduct函數的局部測試,分別為可計算內積與不可計算內積的兩種情形。我們採取的方式是將結果輸出到console,然後自行判讀執行結果是否符合期望。用同樣的方法做更多局部測試,將出現下面的現象:
- 當我們做的局部測試更多時,console輸出將會越來越多,不易判讀結果是否符合期望。
- 為了省寫些test code,你可能會重複使用某些變數,例如前列中的向量u出現在兩個測試裡。你必須很確定u第一次被使用後,仍然有原來的值,否則第二次測試的test code本身就很難說是對的了。
執行一個單元測試的test case,具備下列四步驟:
- 建立測試用資料
- 呼叫待測函數,得到結果值
- 比對預期值與結果值
- 撤掉測試用資料
SP4:以CppUnitLite重作test case。
SP2與SP4二選一,我們將先解SP4。
D步驟:將SP4分割成兩個task:
T9:安裝CppUnitLite。
T10:搬移(與新增)test cases。
C步驟:
依序進行T9(參考資料)與T10。完成T10後,原先在main的test code改變如下:
...
#include "C:\Program Files (x86)\Dev-Cpp\MinGW64\include\cppunitlite\TestHarness.h"
...
int main(int argc, char** argv) {
TestResult tr;
TestRegistry::runAllTests(tr);
/*
... what main should do here
*/
return 0;
}
TEST (computable, innerProduct){
double a[2]={0,1};
double b[2]={1,0};
vector u(2,a);
vector v(2,b);
double prod;
CHECK_EQUAL(true,innerProduct(prod,u,v));
DOUBLES_EQUAL(0,prod,0.00001);
}
TEST (dimension_error, innerProduct){
double a[2]={0,1};
double c[3]={1,2,3};
vector u(2,a);
vector w(3,c);
double prod;
CHECK_EQUAL (true,innerProduct(prod,u,w))
}
main 中兩行紅色的code使用CppUnitLite中的API,執行所有test case(這裡只有兩個)。
我蓄意讓第二個test case驗證失敗: 向量u的 dimension為2,向量w的 dimension為3,所以innerProduct還傳的實際值(return value)為false,但我將期望值設為true。執行後,console畫面如下:
看畫面第一列,我們的得到驗證失敗的原因(Failure: "expected true but was false")、發生的地方(line 123 in main.cpp)。值得注意的是第一個test case驗證通過,故無任何訊息。最後總計失敗的次數,共計一次。
比較原test code執行後console畫面,好壞立見:
console上每一列輸出,都需要靠你自己判讀是否正確。如果判定為有錯,你得自己尋找錯誤發生在哪裡。想像你跑了100個測試,這個判讀/尋找的任務看起來還挺辛苦且易錯的!
L步驟:OK,test code與main函數已分開。再次以programmer的觀點進行回顧。現在,這個功能簡單的程式達到120 Lines的規模。在裡面進行修改、新增code,經常需滾動IDE編輯視窗,programmer犯錯的機率升高。此外,啟動unit testing的API仍然與佔據main函數,需與main該做的事互相切換。
© Y C Cheng, 2013. All rights reserved.