Testcomplete4测试delphi应用程序的实现
Author:wuguofeng
Date:
Testcomplete能进行单元测试、性能测试、功能测试,能很好的识别Borland Delphi、C++Builder、Sybase
PowerBuilder 、Java 、.NET开发的应用程序,像TDBGrid这种难以处理和不是标准的Win32控件也可以很好的支
持。Testcomplete有强大的脚本编写能力,支持Jscript、 C++Script、C#Script、DelphiSript、VBScript等多种脚本
语言,还能实时的对脚本进行语法检查。下面通过一个实际的例子如何使用testcomplete4对Delphi应用程序进行
脚本的录制;建立图片、属性值的检查点;向TDBGrid控件输入和获取信息;从CSV文件中读取用例数据;从
数据库中获取预期结果。
被测程序“MastApp”是安装Delphi时自带的一个示例程序,在Delphi的安装目录\ Borland\Delphi6\Demos\Db
下可以找到
测试任务是:
-
1、新建一个订单,选择一个被开订单的消费者名称,验证显示的消费者号码(CustNo)和地址是否正确;
-
2、从产品信息界面的列表中获得所有的产品编号(PartNo),并随机的选择一个产品编号输入到订单详细列表
的PartNo字段中。 -
3、从CSV文件中读取数量(Qty)和折扣(Discount)输入到订单详细列表中,从列表中获取销售单价
(SellPrice),计算出预期总额,并与实际显示的总额(ExtPrice)进行比较。 -
4、查询数据库验证录入的订单信息有没有正确的保存。
-
在脚本录制之前把三个testcomplete对Delphi的扩展库文件加入到被测程序的项目中,这三个文件:
TCOpenApp.pas、tcOpenAppClasses.pas、tcPublicInfo.pas在testcomplete的安装目录Automated QA\TestComplete 4
\Open Apps\Delphi&BCB下可以找到,并在Delphi的编译器的Project菜单下Options进行如下设置:
-
把Linker tab 页的Include TD32 debug info勾上,然后重新编译生成新的应用程序。这些操作只是针对Delphi开发
的应用程序。 -
现在开始脚本的录制,运行testcomplete4,单击菜单“File”|“New”|“New Project”,在弹出的“Create New
Project”界面中选择“General-Purpose Test Project”模板,项目名称、保存路径、测试套名称自己定,脚本语言选
择“DelphiScript”,单击“OK”,“Finish”,现在已经新建完成了一个测试项目,在左边的“Project Explorer”资
源管理器中的“TestedApps”上单击右键点击“Add”|“New Item”把被测程序加进来,在被测程序名上右击,点
击“Run”运行被测程序,单击工具栏上的 录制按钮开始脚本的录制,录制的脚本如下:
procedure Test1;
var p1 : OleVariant;
var w1 : OleVariant;
var w2 : OleVariant;
begin
p1 := Sys.Process('mastapp');
p1.VCLObject('MainForm').VCLObject('OrderBtn').Click(42, 28);
w1 := p1.VCLObject('EdOrderForm').VCLObject('HeaderPanel');
w1.VCLObject('CompanyCombo').Click(150, 10);
w2 := p1.Window('TPopupDataList', '', 1);
w2.VScroll.Pos := 0;
w2.Click(55, 61);
//对CustNo建立了一个属性值检查点。
if not Objects.Compare(Sys.Process('mastapp').VCLObject('EdOrderForm').VCLObject('HeaderPanel').VCLObject('CustNoEdit'), 'VCLObject_CustNoEdit_') then
Log.Error('Objects are not identical.');
//对消费者地址建立了一个图片检查点。
if not
Regions.Compare('addres.bmp',Sys.Process('mastapp').VCLObject('EdOrderForm').VCLObject('HeaderPanel').VCLObject('CustAdd1Edit')) then
Log.Error('The regions are not identical.');
w1.VCLObject('SoldByCombo').Click(99, 8);
w2 := p1.Window('TPopupDataList', '', 1);
w2.VScroll.Pos := 0;
w2.Click(42, 49);
w1.VCLObject('ItemsGrid').Click(47, 26);
end;
-
上面通过脚本录制创建了两个检查点,创建属性值检查点的方法是单击“Recording”工具栏上的“Stores object
properties”
在弹出的“Add Text to Script”界面上单击“Add”把自动生成的代码添加到脚本中。
-
创建图片检查点的方法类似,只是单击“Recording”工具栏上的 ,单击 保存图片。
-
在脚本中编写两个函数:“readfile”、“queryDb”
//========================================================
//函数readfile用于读取指定文件的内容并传给数组
//输入参数filename是要获取内容的文件名
//输出参数Result
//========================================================
function readfile(filename: string):olevariant;
const
forreading =1;
forwriteing =2;
forappending=8;
var
fs,f :olevariant;
//在testcomplete中定义数组必须指定数组的长度,这是一个很不方便的地方。
txtary : array[1..3]of string ;
i : integer;
begin
fs:=sys.oleobject('scripting.filesystemobject');
f:=fs.opentextfile(filename,forreading,true);
while not f.atendofstream do
begin
for i:=1 to 3 do
begin
txtary[i]:=f.readline;
end;
end;
result:=txtary;
end;
//==============================================================
//函数 queryDb 从数据库中获取数据
//输入参数 databasename指定的数据库名,cmdtxt所要执行的命令语句。
//输出参数result类型为数据集
//==============================================================
function queryDb(databasename: string,cmdtxt:string):olevariant;
var
cmd : olevariant;
S:string;
begin
{ cmd:=ado.createadocommand;
//访问Access数据库使用下面的连接信息。
cmd.connectionstring:='provider=microsoft.jet.oledb.4.0;data source=' + databasename;
//查询MSSQL数据库使用下面的连接信息。
// cmd.connectionstring:='provider=SQLOLEDB;persist security info=false;data source='+
//databasename +';user id=sa;password=sa;initial catalog=this4';
cmd.commandtype:=cmdtext;
cmd.commandtext:=cmdtxt;
result:=cmd.execute;}
//BDE数据库使用下面的代码。
cmd:=BDE.createquery;
cmd.databasename:=databasename;
cmd.sql:=cmdtxt;
cmd.open;
cmd.first;
S:='';
while not VarToBool(cmd.EOF) do
begin
for i := 0 to cmd.FieldCount - 1 do
S := S + cmd.Field(i).AsString ;
// S := S + Chr(13) + Chr(10);
cmd.next;
end;
result:=S;
end;
-
对脚本进行扩充修改如下:
-
procedure main;
const
fi='c:\GridData.csv';
var p1,w1,w2 : OleVariant;
pic,facttotal,expecttotal,subtotal :olevariant;
var ds:olevariant;
var i,x,y: integer;
inqty:integer; //输入的数量
indis:string; //输入的折扣
noary : array[1..59]; //用于保存所有的产品编号,数组必须定义长度真是不方便.
caseary :array[1..4]; //保存从文件读取的用例数据
partary :array[1..4]; //保存定单的产品编号
tmp,datastr,sqlstr,dbname,itemtotal: string;
partcut,orderno:olevarint;
begin
p1 := Sys.Process('mastapp');
p1.VCLObject('MainForm').VCLObject('OrderBtn').Click(42, 28);
w1 := p1.VCLObject('EdOrderForm').VCLObject('HeaderPanel');
w1.VCLObject('CompanyCombo').Click(150, 10);
w2 := p1.Window('TPopupDataList', '', 1);
w2.VScroll.Pos := 0;
w2.Click(55, 61);
if not Objects.Compare(Sys.Process('mastapp').VCLObject('EdOrderForm').VCLObject('HeaderPanel').VCLObject('CustNoEdit'), 'VCLObject_CustNoEdit_') then
Log.Error('Objects are not identical.');
if not Regions.Compare('addres.bmp', Sys.Process('mastapp').VCLObject('EdOrderForm').VCLObject('HeaderPanel').VCLObject('CustAdd1Edit')) then
Log.Error('The regions are not identical.');
w1.VCLObject('SoldByCombo').Click(99, 8);
w2 := p1.Window('TPopupDataList', '', 1);
w2.VScroll.Pos := 0;
w2.Click(42, 49);
//使订单Grid获得焦点,这里使用的是坐标值但并不影响Grid的识别,
//因为它是相对于Grid的位置而不是整个屏幕。
w1.VCLObject('ItemsGrid').Click(47, 26);
w2 := w1.VCLObject('ItemsGrid');
//获得产品信息界面中所有的产品编号,保存在数组noary中。
w1:=p1.VCLObject('SearchDlg').VCLObject('DBGrid1');
//通过DBGrid的dataset数据集属性取得数据。
ds:=w1.datasource.dataset;
ds.first;
while not vartobool(ds.eof) do
begin
for i:=1 to ds.recordcount do
begin
noary[i]:=ds.fields.fields[0].asvariant;
ds.next;
end;
end;
//调用读文件函数
caseary:= readfile(fi);
subtotal:=0;
//向定单列表中插入数据,vararrayhighbound函数获得数组的长度。
for x:=1 to vararrayhighbound(caseary,1) do
begin
tmp:=caseary[x];
//POS函数用来取得","在字符串中第一次出现的位置
//COPY函数从字符串中截取指定位置和长度的字符
y:=pos(',',tmp);
inqty:=copy(tmp,0,y-1);
indis:=copy(tmp,y+1,length(tmp));
//单击界面上的新增按钮
p1.VCLObject('EdOrderForm').VCLObject('Speedbar').VCLObject('DBEditBtns').VCLObject('TNavButton_5').click;
//随机获取一个产品编号,输入DBGrid中
i:=random(2,59);
w2.keys(noary[i]);
w2.keys('[Enter]');
partary[x]:=noary[i];
w2.keys('[Right][Right]');
//获取DBGrid中的单价。
pic:=w2.selectedfield.text;
w2.keys('[Right]');
//输入数量。
w2.keys(inqty);
w2.keys('[Enter]');
w2.keys('[Right]');
//输入折扣。
w2.keys(indis);
w2.keys('[Enter]');
w2.keys('[Right]');
//获得界面实际显示的小计。
facttotal:=w2.selectedfield.text;
subtotal:=subtotal+facttotal;
//计算预期的小计,vartofloat类型转换函数。
expecttotal:=(vartofloat(pic)*inqty-(vartofloat(pic)*inqty*(strtofloat(indis)*0.01)));
//实际的与预期的进行对比。
if facttotal=expecttotal then
//向测试结果报告中写入信息。
log.message('第 '+ inttostr(x) +' 订单小计计算正确')
else
log.error('第 '+ inttostr(x) +' 订单小计计算错误,实际显示的:'+ vartostr(facttotal)+',预期的:'+vartostr(expecttotal));
w2.keys('[Left][Left][Left][Left][Left]');
end;
//单击保存按钮。
w1:=p1.VCLObject('EdOrderForm').VCLObject('HeaderPanel');
w1.VCLObject('PostBtn').click;
//获得定单号。
orderno:=p1.VCLObject('EdOrderForm').VCLObject('DBText1').text;
dbname:='dbdemos';
//调用数据库查询函数,查出数据库中的订单总额。
sqlstr:='select itemstotal from orders where orderno='+orderno;
itemtotal:=querydb(dbname,sqlstr);
//查询数据库中订单详细数量。
sqlstr:='select count(*) from items where orderno='+orderno;
partcut:=querydb(dbname,sqlstr);
//比较实际的与数据库中的总额。
if itemtotal=subtotal then
log.message('数据库中的总金额正确')
else
log.error('数据库中的总金额错误');
//比较订单的详细数量。
if partcut=vararrayhighbound(partary,1) then
log.message('数据库中的明细正确')
else
log.error('数据库中的明细错误');
end;
相关宝贝 | |||||||||||||||||||||||||||||||||
|