单元测试几个小建议

以下的示例均在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;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值