以下的示例均在DUNIT下進行,但同樣適用於XUNIT。只是語法用的是OBJECT PASCAL
最近在用DUNIT來寫程序,寫着寫着,也碰到了一些小問題,也找到過一些解決辦法,同時,也發現了不少的注意事項,特提出來與大家共勉。
1、最好用帶ID的異常來代替顯示對話框。
優點:對話框無法進行捕捉。異常可以
缺點:程序內部要加入異常處理機制,並要求拋出,代碼量增加
舉例:
當系統發現某員工不存在時,顯示‘該員工不存在,不能繼續’,這對應用程序來說沒有什麼問題,但如果在單元測試裏面要進行操作,就必須要得到這個提示或者以其它可以返回的狀態進行返回,加狀態字非常麻煩,我們可以定義一個異常類,然後,再進行拋出。這樣,在進行單元測試的時候,就可以進行捕捉了。
EDisplayException = class(Exception)
public
ErrorID: Integer;
constructor Create(Msg: string; ID: Integer); virtual;
end;
constructor EDisplayException.Create(Msg: string; ID: Integer);
begin
ErrorID := ID;
Inherited Create(Msg);
end;
使用的時候,就可以在單元測試方法裏進行
try
..
except
on e: EDisplayException do
begin
e.errorid.... 就可以想做什麼就做什麼
end
2、分離窗體與程序
因爲窗體與程序結合得非常緊密的話,必須要做大量的手工操作,就達不到DUNIT自動測試的效果了。比如我們有這麼一段代碼。
procedure T1.Check(AType: string);
var
tmpStr: string;
begin
tmpStr := InputBox('測試', '輸入', tmpStr);
......
end
因爲前面有一段要求用戶手工錄入的過程,使得我們的自動測試不好做,我們最好將它分離成兩個過程。
procedure T1.Check(AType: string);
var
tmpStr: string;
begin
tmpStr := InputBox('測試', '輸入', tmpStr);
T2(AType, tmpStr);
end
procedure T2.Check(AType: string; AValue: string);
begin
..
end
這樣,我們寫測試的時候,只要測試T2就可以了。
3、注意方法的顯示域。我們在單元測試的時候,可能經常需要測試到一個PRIVATE的方法,雖然不是非常喜歡,但還是會測試到,但我們的應用程序卻不允許它在PRIVATE裏面,怎麼辦呢,最好的辦法是加一個編譯指令,比如
TSign = class
{$IFDEF UNITTEST}
public
{$ELSE}
private
{$ENDIF}
SignPrint: Boolean;
WorkerMustExists: Boolean;
在我們的單元測試的工程裏面定義UNITTEST。
這樣就解決了我們需要的問題了。
4、獨立初始與判定。
對於可能會多次測試的項目,最好將初始化條件以及最後判定結果獨立。這樣可以使得它們重用。
比如我們有這樣的一個方法。
procedure TMyTest.Test1//對TMy測試
begin
...一大堆初始化
My.Do;//這是調用被測試項。
Check(..)..
Check(..)..又一大堆判定
end;
在我們的程序裏面,可能另外有TMy2的Test3調用了TMy的Test1方法,對初始化變量還得做一次,我們將初始化及結果分離出來,就可以兩面兼顧了。形如
TDataSwitchCheck = class
public
class procedure BeginDownSet;
class procedure CheckDownSet(ACase: TTestCase);
end;
class procedure TDataSwitchCheck.BeginDownSet;
begin
//先刪除服務器上的.
SystemSetup.ServerAccess.ExecSQL('delete from p_pos_setup where dsection = ''單元測試''');
SystemSetup.ServerAccess.ExecSQL('insert into p_pos_setup(dsection, dident, dvalue, dpos) '
+ 'values(''單元測試'', ''測試'', ''測試'', ''99'')');
SystemSetup.ServerAccess.ExecSQL('insert into p_pos_setup(dsection, dident, dvalue, dpos) '
+ 'values(''單元測試'', ''測試'', ''測試'', ' + QuotedStr(SystemSetup.PosNo) + ')');
//刪除本地上的
SystemSetup.ClientAccess.ExecSQL('delete from p_pos_setup where dsection = ''單元測試''');
end;
class procedure TDataSwitchCheck.CheckDownSet(ACase: TTestCase);
var
tmpString: string;
begin
SystemSetup.ClientAccess.GetSQLValue('select dsection from p_pos_setup where dsection = ''單元測試'' and dpos = ' + QuotedStr(SystemSetup.PosNo) , tmpString);
ACase.Check(tmpstring = '單元測試', '下載本POS機設置錯誤');
SystemSetup.ClientAccess.GetSQLValue('select dsection from p_pos_setup where dsection = ''單元測試'' and dpos = ''99''', tmpString);
ACase.Check(tmpstring = '', '下載了不屬於本POS機設置錯誤');
end;
//以下是測試用例
procedure TDataSwitchTests.TestDownSet;
begin
TDataSwitchCheck.BeginDownSet; //初始化
SystemSetup.DataSwitch.DownSet(nil);// 這是被測試的一個方法。
TDataSwitchCheck.CheckDownSet(Self) //檢查結果
end;
//另一個測試用例。
procedure TFrm_DataSwtichTests.TestStartSwtich;
begin
TDataSwitchCheck.BeginDownRight;
TDataSwitchCheck.BeginDownSet;
TDataSwitchCheck.BeginDownKey;
TDataSwitchCheck.BeginUpdateSet;
TDataSwitchCheck.BeginSaleDataUp;
TFrm_DataSwtich.AllDataSwtich;
TDataSwitchCheck.CheckDownRight(Self);
TDataSwitchCheck.CheckDownSet(Self);
TDataSwitchCheck.CheckDownKey(Self);
TDataSwitchCheck.CheckUpdateSet(Self);
TDataSwitchCheck.CheckSaleDataUp(Self);
end;