TestComplete Tips
请来信索取最新版本(Email:quicktest##qq.com( 请把##改为@ ))
1、如何在TestComplete中用Jscript的类封装窗口定义
参考:
《TestComplete ( JScript ): Making windows definitions using wrapper classes》
http://autotestgroup.com/en/blog/69.html
2、如何控制鼠标进行拖拽操作?
function DragDrop(obj, deltaX, deltaY)
{
var iX = obj.ScreenLeft + obj.Width/2;
var iY = obj.ScreenTop + obj.Height/2;
Log.Picture(obj.Picture(), "Object to be moved");
obj = Sys.Desktop.ObjectFromPoint(iX + deltaX, iY + deltaY);
Sys.Desktop.MouseDown(VK_LBUTTON, iX, iY);
obj.HoverMouse(obj.Width/2, obj.Height/2);
Sys.Desktop.MouseUp(VK_LBUTTON, iX + deltaX, iY + deltaY);
}
function Test3()
{
var w1 = Sys.Process("Explorer").Window("Shell_TrayWnd").Window("ToolbarWindow32", "Quick Launch");
DragDrop(w1, -30, -20);
}
参考:
《TestComplete: when method Drag doesn't work》
http://autotestgroup.com/en/blog/61.html
3、如何在TestComplete中让Jscript的typeof返回“date”、“array”类型?
function _typeof(value)
{
switch(typeof(value))
{
case "string":
return (value.match(/\d{1,2}[\/.-]\d{1,2}[\/.-]\d{2,4}/) != null) ? "date" : "string";
break;
case "object":
try
{ value.join() }
catch(e)
{
if(e.number == -2146827850)
return "object"
else
throw e;
}
return "array";
break;
default:
return typeof(value);
}
}
参考:
《TestComplete:improving Jscript typeof operator》
http://autotestgroup.com/en/blog/46.html
4、如何在延迟脚本执行时显示剩余时间?
function Sleep(iSeconds)
{
i = iSeconds;
while(i > 0)
{
BuiltIn.Delay(500);
Indicator.PushText("Delaying script execution for " + iSeconds + " seconds. " + i + " seconds left");
BuiltIn.Delay(500);
i -= 1;
}
Indicator.Clear();
}
参考:
《TestComplete:delaying script execution》
http://autotestgroup.com/en/blog/42.html
5、如何定时检查某个窗口是否出现,如果出现则关闭它?
// TestComplete JScript
function KillCalculator()
{
if(Sys.WaitProcess("calc", 1, 1).Exists)
{
Log.Message("Calculator has been found");
Sys.Process("calc").Terminate();
}
}
function test_timer()
{
Utils.Timers.Add(500, "MyUnit.KillCalculator", true);
BuiltIn.Delay(60000);
}
参考:
《TestComplete:Closing Unexpected Windows》
http://autotestgroup.com/en/blog/28.html
6、如何用TC处理IE的文件下载窗口?
function MegaClick( obj )
{
for( i = 1; i <= 2; i++ )
{
if( obj.Focused )
obj.Parent.Keys( "[Tab]" );
while( !obj.Focused )
obj.Parent.Keys( "[Tab]" );
}
obj.Click();
}
参考:
《A strange behavior of the File Download window》
http://autotestgroup.com/en/blog/23.html
7、TestComplete的ClickButton()方法
录制按钮点击时一般TestComplete会生成ClickButton方法,例如:
var w = Sys.Process("WindowsApplication3"). WinFormsObject("Form1");
w.WinFormsObject("button1").ClickButton();
建议替换成Click(),因为标准按钮可能会被替换成自定义的控件或第三方的控件,而使用了相同的名字,这种情况下ClickButton可能会工作不正常。
参考:
http://autotestgroup.com/en/blog/17.html
8、在TestComplete中如何读写Excel?
用Jscript可以这样写:
function TestExcelClass()
{
// specifying excel file name and deleting it, if it is already exists
var excel = new ExcelClass("C:\\temp.xls");
if(Utilities.FileExists(excel.FileName))
{
Utilities.DeleteFile(excel.FileName);
}
// creating new Excel file with the specified name and predefined sheets
var arrSheets = new Array("MySheet1", "MySheet2", "MySheet3", "MySheet4");
excel.CreateFile(null, arrSheets);
// writing data to the created Excel file by different ways
excel.Write("MySheet1", 1, 1, "text in row 1, column 1");
excel.Write("MySheet1", 1, "B", "text in row 1, column 'B'");
excel.WriteCell("MySheet1", "C1", "text in cell 'C1'");
// specifying data for "matrix writing"
var arrRow1 = new Array("text1", "text2", "text3");
var arrRow2 = new Array("text4", "text5", "text6");
var arrMatrix = new Array(arrRow1, arrRow2);
excel.WriteMatrix("MySheet1", 3, "A", arrMatrix);
// reading written data using different methods
Log.Message("Text in cell A1", excel.ReadCell("MySheet1", "A1"));
Log.Message("Text in cell B1", excel.Read("MySheet1", 1, 2));
Log.Message("Text in cell C1", excel.Read("MySheet1", 1, "C"));
var arrNew1 = excel.ReadMatrix("MySheet1", 3, "A", 4, "C");
Log.Message("Matrix data", arrNew1[0].join(" ") + "\n" + arrNew1[1].join(" "));
var arrNew2 = excel.ReadCells("MySheet1", "A1", "C1", "A4", "C4");
Log.Message("Data from several cells", arrNew2.join("\n"));
}
ExcelClass类的代码如下:
// Automated Testing Service Group
// Excel class
// Global variables
var oExcel = Sys.OleObject("Excel.Application");
function ExcelClass(sFileName)
{
// - - - - variables
var oWorkbook, oSheet, i;
// - - - - properties
this.FileName = (sFileName == null? "" : sFileName);
this.DefaultSheet = "Sheet1";
this.MaxColumns = 256;
this.MaxRows = 65536;
oExcel.ScreenUpdating = false;
//oExcel.DisplayAlerts = false;
//oExcel.Interactive = false;
// - - - - public methods
this.CreateFile = function(sFileName, aSheets)
{
if(sFileName != null)
{ this.FileName = sFileName }
if(Utilities.FileExists(this.FileName))
{
Log.Warning("File is already exist", "You are trying to create a new file which is already exist\n" + this.FileName);
return true;
}
try
{
oWorkbook = oExcel.Workbooks.Add();
if(aSheets != null)
{
Log.Message("Creating " + aSheets.length + " new sheets");
if(aSheets.length > oWorkbook.Sheets.Count)
{
for(i = oWorkbook.Sheets.Count+1; i <= aSheets.length; i++)
{ oWorkbook.Sheets.Add(); }
}
for(i in aSheets)
{
oWorkbook.Sheets(Number(i)+1).Name = aSheets[i];
}
}
oWorkbook.SaveAs(this.FileName);
oWorkbook.Close();
//oExcel.Quit();
}
catch(e)
{
Log.Error("An exception occured, see remarks", "Exception number: " + e.number + "\nException description: " + e.description)
}
}
this.Write = function(sSheet, iRow, Col, value)
{
if(sSheet == null) sSheet = this.DefaultSheet;
var iCol = typeof(Col) == "string" ? this.ConvertColName(Col) : Col;
try
{
oWorkbook = oExcel.Workbooks.Open(this.FileName);
oWorkbook.Sheets(sSheet).Cells(iRow, iCol).value = value;
oWorkbook.Save();
oWorkbook.Close();
}
catch(e)
{
Log.Error("An exception occured, see remarks", "Exception number: " + e.number + "\nException description: " + e.description);
}
}
this.Read = function(sSheet, iRow, Col)
{
var iCol = typeof(Col) == "string" ? this.ConvertColName(Col) : Col;
oWorkbook = oExcel.Workbooks.Open(this.FileName);
var value = oWorkbook.Sheets(sSheet).Cells(iRow, iCol).value;
oWorkbook.Close();
return value;
}
this.ReadRow = function(sSheet, iRow, iMaxColumns)
{
var aRet = new Array();
var i;
if(iMaxColumns == null) iMaxColumns = this.MaxColumns;
if(sSheet == null) sSheet = this.DefaultSheet;
oWorkbook = oExcel.Workbooks.Open(this.FileName);
for(i = 1; i <= iMaxColumns; i++)
{
aRet.push(oWorkbook.Sheets(sSheet).Cells(iRow, i).value);
}
oWorkbook.Close();
return aRet;
}
this.ReadCol = function(sSheet, Col, iMaxRows)
{
var aRet = new Array();
var i;
if(iMaxRows == null) iMaxRows = this.MaxRows;
if(sSheet == null) sSheet = this.DefaultSheet;
var iCol = typeof(Col) == "string" ? this.ConvertColName(Col) : Col;
oWorkbook = oExcel.Workbooks.Open(this.FileName);
for(i = 1; i <= iMaxRows; i++)
{
aRet.push(oWorkbook.Sheets(sSheet).Cells(i, iCol).value);
}
oWorkbook.Close();
return aRet;
}
//
this.ReadMatrix = function(sSheet, iRowStart, ColStart, iRowEnd, ColEnd)
{
var i, j;
var arr = new Array();
var aRet = new Array();
var iColStart = typeof(ColStart) == "string" ? this.ConvertColName(ColStart) : ColStart;
var iColEnd = typeof(ColEnd) == "string" ? this.ConvertColName(ColEnd) : ColEnd;
oWorkbook = oExcel.Workbooks.Open(this.FileName);
for(i = iRowStart; i <= iRowEnd; i++)
{
for(j = iColStart; j <= iColEnd; j++)
{
arr.push(oWorkbook.Sheets(sSheet).Cells(i, j).value);
}
aRet.push(arr);
arr = new Array();
}
oWorkbook.Close();
return aRet;
}
this.WriteMatrix = function(sSheet, iRowStart, ColStart, aData)
{
var i, j;
var iColStart = typeof(ColStart) == "string" ? this.ConvertColName(ColStart) : ColStart;
var iCol = iColStart;
var iRow = iRowStart;
oWorkbook = oExcel.Workbooks.Open(this.FileName);
for(i = 0; i < aData.length; i++)
{
for(j = 0; j < aData[i].length; j++)
{
oWorkbook.Sheets(sSheet).Cells(iRow, iCol).value = aData[i][j];
iCol++;
}
iCol = iColStart;
iRow++;
}
oWorkbook.Save();
oWorkbook.Close();
}
//
this.ReadCells = function(sSheet)
{
var aRet = new Array();
var i;
if(sSheet == null) sSheet = this.DefaultSheet;
for(i = 1; i < arguments.length; i++)
{
aRet.push(this.Read(sSheet, this.ConvertCellName(arguments[i]).row, this.ConvertCellName(arguments[i]).col));
}
return aRet;
}
//
this.WriteCell = function(sSheet, sCell, value)
{
var arr = this.ConvertCellName(sCell);
this.Write(sSheet, arr.row, arr.col, value);
}
//
this.ReadCell = function(sSheet, sCell)
{
var arr = this.ConvertCellName(sCell);
return this.Read(sSheet, arr.row, arr.col);
}
// - - - - private methods
this.ConvertCellName = function(sCellName)
{
var aRet = new Array();
var i;
for(i = 0; i < sCellName.length; i++)
{
if(sCellName.charCodeAt(i) < 64)
{
aRet.row = sCellName.substr(i, sCellName.length);
aRet.col = this.ConvertColName(sCellName.substr(0, i));
break;
}
}
return aRet;
}
this.ConvertColName = function(sColName)
{
var iCol = 0;
switch(sColName.length)
{
case 1:
iCol = sColName.toUpperCase().charCodeAt(0) - 64;
break;
case 2:
iCol = (sColName.toUpperCase().charCodeAt(0) - 64)*26 + (sColName.toUpperCase().charCodeAt(1) - 64);
break;
case 3:
iCol = (sColName.toUpperCase().charCodeAt(0) - 64)*676 + (sColName.toUpperCase().charCodeAt(1) - 64)*26 + (sColName.toUpperCase().charCodeAt(2) - 64);
break;
case 4:
iCol = (sColName.toUpperCase().charCodeAt(0) - 64)*17576 + (sColName.toUpperCase().charCodeAt(0) - 64)*676 + (sColName.toUpperCase().charCodeAt(1) - 64)*26 + (sColName.toUpperCase().charCodeAt(2) - 64);
break;
default:
Log.Error("Column name '" + sColName + "' cannot be converted");
break;
}
return iCol;
}
}
参考:
http://autotestgroup.com/en/materials/16.html
9、在用TestComplete测试时如何自动统计代码覆盖率?
可以结合Ncover进行代码覆盖率的自动统计
参考:
http://docs.ncover.com/how-to/running-ncover-with-your-unit-testing-framework/testcomplete/
10、用Exists属性判断窗口是否存在时,如果窗口不存在会自动写入一条错误日志,如何避免,改为写入自己的日志?
用Exists属性判断窗口是否存在:
Sys["Process"]("flight4a")["Window"]("#32770","Login", 1)["Exists"]
会自动写入错误日志:
Cannot obtain the window with the windowclass '#32770', window caption 'Login' and index 1.
改用WaitWindow:
function Test1()
{
loginWindow = Sys["Process"]("flight4a")["WaitWindow"]("#32770","Login", 1)
if(loginWindow["Exists"])
Log["Message"]("Exists");
else
Log["Error"]("NotExists")
}
11、加快TestComplete执行速度的Tips
是什么原因导致TestComplete的脚本执行速度不够快呢?这要从TestComplete的3个方面进行了解:
1、TC在查找对象树时,如果对象不存在,TC会等待一段时间看对象是否出现。
2、找到对象后,TC将分析对象的类型,然后给对象附加各种可能的方法和属性,这可能要消耗很多的时间,例如对于一个.NET控件对象,除了提取普通的属性和方法外,TC还会看控件对象是否暴露了MSAA、UI Automation等方面的属性和方法,有的话也会一并添加。
3、有时候TC的脚本执行速度会受到界面控件性能的影响,例如展开一个TreeView控件时,如果Item比较多,而且使用了一些动态效果来重画的话,则TC要等待这些动作完成才能执行下一条语句。
知道了TC的执行效率受制约的因素后,我们就可以考虑从以下几个方面对TC进行“加速”
1. 把TC中有些不需要的插件屏蔽掉。
2. 过滤掉那些不需要使用的应用程序进程。
3. 如果不需要的话,请把Debug Agent关闭。
4. 优化Wait选项和方法的使用。
5. 调整Delay选项。
6. 在操作系统中调整Double-Click的速度。
7. 关闭Windows的界面视觉效果。
8. 使用其他方法替代模拟用户操作,例如用Keys替代Sys.DeskTop.KeyDown和Sys.DeskTop.KeyUp。
9. 优化low-level 的录制脚本,剔除一些无用的操作和延时。
参考:http://www.automatedqa.com/techpapers/test_playback_performance_tips.asp
12、CheckPoint
Tip 3 - Checkpoints
As you’re recording your tests,you’ll want to verify that your application is behaving properly.TestComplete’s Checkpoints verify that: information has rendered properly onscreen; information has been successfully written to a database; a web servicereturns the correct value; and much more.
In Keyword test mode, there’s acheckpoint operations panel that lists all available checkpoints. Simply dragthe desired checkpoint onto the test panel and follow the prompts provided bythe wizard that’s displayed.
If you’re not sure which checkpointyou should use, there’s a CheckpointWizard that asks a series of simple questions to help youdecide which checkpoint is right for a given test. A series of videos thatdescribe some of TestComplete’s checkpoints can be seen here:
http://www.automatedqa.com/products/testcomplete/screencasts/
13、如何读写COM端口?
Sub TestCOMPort
Const ForWriting = 2, TriStateFalse = 0
Dimfso, f
Setfso = CreateObject("Scripting.FileSystemObject")
Setf = fso.OpenTextFile("COM1:", ForWriting, False, TriStateFalse)
'Write data to the port
f.Write Chr(26)
f.Write Chr(32)
f.Write Chr(27)
f.Close
End Sub
or
Sub Test
Dim Port, i, s
Set Port =dotNET.System_IO_Ports.SerialPort.zctor_4("COM1", 9600)
Port.Open
' Writing data to the port
Port.Write "A " & Chr(27)
' Waiting for response
aqUtils.Delay 1000
' Processing response
If Port.BytesToRead <> 0 Then
s = Port.ReadExisting
Log.Message s
Else
Log.Warning "No data"
End If
Port.Close
End Sub
14、如何表示十六进制?
VBScript中可以用类似&HFF的格式表示十六进制数
15、怎么判断一个对象是否存在某个属性?
用aqObject.GetProperties
例:
Set p =Sys.Process("MyApplication")
Set props = aqObject.GetProperties(p)
While props.HasNext
Setprop = props.Next
Log.Message prop.Name & ": " & aqConvert.VarToStr(prop.Value)
Wend
16、如何执行ClickOnce应用程序?
http://www.automatedqa.com/support/viewarticle/?aid=17600
Sub RunClickOnceApplication()
Dimpath
path = "<pathToTheApplication>" ' e.g. "c:\SampleClickOnce\sample.appref-ms" SetWshShell = CreateObject("WScript.Shell")
WshShell.Run("rundll32.exe dfshim.dll,ShOpenVerbShortcut "& path)
End Sub
17、如何获取当前测试日志?
http://www.automatedqa.com/support/viewarticle.aspx?aid=9047
Sub Test()
Call Log.Message("Currentlog items", GetLogItems())
End Sub
Function GetLogItems()
Dim tempFolder, xDoc,result
tempFolder = aqEnvironment.GetEnvironmentVariable("temp")& "\" &_
GetTickCount() & "\"
If 0 <> aqFileSystem.CreateFolder(tempFolder)Then
Log.Error("The " &tempFolder & " temp folder was not created")
GetLogItems = ""
Exit Function
End If
If Not Log.SaveResultsAs(tempFolder,lsHTML) Then
Log.Error("Log was not exported tothe " & tempFolder & " temp folder")
GetLogItems = ""
Exit Function
End If
Set xDoc = Sys.OleObject("MSXML2.DOMDocument.4.0")
xDoc.load(tempFolder &"root.xml")
result =LogDataToText(xDoc.childNodes.item(1), 0, " ")
Call aqFileSystem.DeleteFolder(tempFolder,True)
GetLogItems = result
End Function
Function LogDataToText(logData, indentIndex,indentSymbol) Dim i, result
If "LogData"<> logData.nodeName Then
LogDataToText =""
Exit Function
End If
result = ""
For i = 0 ToindentIndex - 1
result = result &indentSymbol
Next
result = result & "Name:" & logData.getAttribute("name") & ", status:" &_
GetTextOfStatus(logData.getAttribute("status")) & vbCrLf
For i = 0 TologData.childNodes.length - 1
result = result &LogDataToText(logData.childNodes.item(i),_
indentIndex + 1, indentSymbol)
Next
LogDataToText = result
End Function
Function GetTextOfStatus(statusIndex)
Select CasestatusIndex
Case "0"GetTextOfStatus = "OK"
Case "2"GetTextOfStatus = "FAILED"
Case ElseGetTextOfStatus = "UNDEFINED"
End Select
End Function
18、如何检查COM对象是否已经注册?
http://www.automatedqa.com/support/viewarticle/?aid=17606
Sub Test1()
Dim objName
objName = "C:\ProgramFiles\Automated QA\TestComplete 8\Bin\TestComplete.exe"
If(IsCOMObjectRegistered("localhost", objectName)) Then
Call Log.Message("Anobject is registered")
Else
Call Log.Error("Anobject was not registered")
End If
End Sub
Function IsCOMObjectRegistered(computerName, objectPath)
Dim wmiService,wmiObjectPath, objectsList
Set wmiService =GetObject("WinMgmts:{impersonationLevel=impersonate}!\\" &_
computerName & "\root\cimv2")
wmiObjectPath =Replace(objectPath, "\", "\\")
Set objectsList = wmiService.ExecQuery("SELECT* FROM " &_
"Win32_ClassicCOMClassSetting WHERE LocalServer32='" &wmiObjectPath & "'")
IsCOMObjectRegistered = False
For Each ObjService inObjectsList
IsCOMObjectRegistered = True
Exit Function
Next
End Function
19、如何通过命令行传入参数给TestComplete的脚本进行处理?
Pass parameters via the command line
http://www.automatedqa.com/support/viewarticle.aspx?aid=9021
Sub ProcessCommandLine
For i = 1 To BuiltIn.ParamCount
ProcessCommandLineArgument BuiltIn.ParamStr(i)
Next
End Sub
Sub ProcessCommandLineArgument(arg)
Dim items
items = Split(arg,"=")
If UBound(items)<> 1 Then
Exit Sub
End If
Select Case aqString.ToLower(aqString.Trim(items(0)))
Case"apppath" 'Project.Variables.AppPath= aqString.Trim(items(1))
Log.Message "The 'apppath' argumentis found! The value is '"_
& aqString.Trim(items(1))& "'"
Case"appver" 'Project.Variables.AppVer= aqString.Trim(items(1))
Log.Message "The 'appver' argumentis found! The value is '"_
& aqString.Trim(items(1))& "'"
End Select
End Sub
20、处理非预期窗口的设置
TestComplete - Tip 8 (Handling UnexpectedWindows)
Each of these options is listed in your project’s properties panel, andyou can enable or disable any combination of them according to your uniqueneeds.
21、等待对象
Tip 9 Waiting for Objects
Sometimes you need to have your automated tests pause for a certainlength of time. Maybe you need to wait while your application reads informationfrom a database, or you need to wait for a file to download. TestCompleteoffers several ways for you to delay your tests execution for situations likethis.
First is the Delay command. Thispauses the test for a specific number of milliseconds. In keyword tests, youinsert delays by dragging the Delay operation from the miscellaneous group box.
In a script based test, you can simply enter the word Delay andenter the number of milliseconds you want to wait. Refer to the TestCompletehelp file’s Delay help topic for syntax examples of each language.
You can also pause test execution until a certain window or objectexists onscreen. This is accomplished by using built-in commands likeWaitWindow and WaitChild. A video demonstrating how to use these commands canbe found here: http://www.automatedqa.com/products/testcomplete/screencasts/waiting-objects/
22、如何扩展TestComplete
Tip 11Extensions
TestCompletewas designed to be extensible, and you can create your own custom checkpoints,scripting objects, and helper functions via a feature called Extensions. Theselet you transform complicated or lengthy operations into single clicksolutions. For example, you could create a checkpoint that verified zip codeswere formatted properly, or that temperatures in Celsius were successfullyconverted to Fahrenheit. There are several prebuilt extensions available on ourwebsite:
http://www.automatedqa.com/blogs/post/08-11-20/7-ready-made-test-extensions/
You can learn more about building custom extensions from this video:
http://www.automatedqa.com/products/testcomplete/screencasts/scriptextensions/
23、TestComplete设置断点不生效
可以尝试安装MicrosoftScript Debuger或重新注册PMD.dll,参考:
http://www.automatedqa.com/support/viewarticle/8874/