时间有点晚了,我这里就直接拿出几个最关键的一方
第一,将对象库转换成XML文件,并从中提取出对象字符串,我们输入 的可能仅仅是按钮名称,但需要从中取得对象的整个父对象。
TestDllFilePath=FrameworkPath+"Test_DotNetDll\QTPBuildObjectLayer.dll"
Set FileOperation= DotNetFactory.CreateInstance("System.IO.File")
Set DirectoryOperation= DotNetFactory.CreateInstance("System.IO.Directory")
Set ObjectBuild= DotNetFactory.CreateInstance("QTPBuildObjectLayer.BuildObject",TestDllFilePath)
Set XMLFileExport=CreateObject("Mercury.ObjectRepositoryUtil")
Set TestDataDictionary=CreateObject("Scripting.Dictionary")
这里是前提,需要用不对劲这些外部dll。或者通过dotnetfactory创建,直接高用基于.net的方法
第二,处理对象库及转换成XML.
'FunctionName:BuildObject
'Description:convert object name to string, eg. convert "Login" to window("Main").Winbutton("Login"), description program is supported
'FunctionType:Function Utility , referenced by ActionEntry
Function BuildObject(ObjectName)
If left(ObjectName,3)="Dsc" Then
BuildObject=Dsc_Object(ObjectName) 'reserved
Else
RepositoriesNumTemp=1
For RepositoriesNumTemp=1 to RepositoriesCollection.Count
RepositoryExportToXMLFile RepositoriesNumTemp
ObjectFound = ConvertToObjectLayer(ObjectName)
If ObjectFound <> "" Then
BuildObject = ObjectFound
Exit for
End If
Next
End If
End Function
'FunctionName:LoadRepositories
'Description:if Repositories_Name give a repository,then add it to current actions,else
'FunctionType: Function Utility,referenced by ActionEntry funcion
Sub LoadRepositories(RepositoriesName)
TestRepositoriesFilePath=TestRepositoriesPath+RepositoriesName
If RepositoriesCollection.Find(TestRepositoriesFilePath)=False Then
RepositoriesCollection.Add(TestRepositoriesFilePath)
else
RepositoriesCollection.Remove(TestRepositoriesFilePath)
RepositoriesCollection.Add(TestRepositoriesFilePath)
end if
End Sub
'FunctionName:RepositoryExportToXMLFile
'Description :Export all repositorys to xml files.
'Function Type:Utility Function,referenced by build Object
Sub RepositoryExportToXMLFile(RepositoryIndex)
If FileOperation.Exists(TempXMLFilePath) Then
FileOPeration.Delete(TempXMLFilePath)
End If
XMLFileExport.ExportToXML (FrameworkFolderPath+RepositoriesCollection.Item(RepositoryIndex)),TempXMLFilePath
End Sub
'FuncitonName:ConvertToObjectLayer
'Description:Find object name in temp.xml file and recombine to a string like windows("test").winbutton("hello")
'Function:Function Utilities ,referenced by BuildObject
Function ConvertToObjectLayer(ObjectName)
ObjectArray=ObjectBuild.FilePathObjectName(TempXMLFilePath,ObjectName)
If ObjectArray<>"" Then
ObjectArray=Split(ObjectArray,"@")
ConvertToObjectLayer=ObjectArray(Ubound(ObjectArray))
ELSE
ConvertToObjectLayer=""
End If
End Function
上面可以 看到高有季buildobjeectt方法 ,这个其实是net写的dll.具体 代码如下,这里千万不能如错,为了考虑以后兼容,我在这里返回的是数组。原则QTP对象库中是不要出现两个同名的对象。这个地方是千万不能出错的。为了简单和效率就用了linq to xml.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Xml.Linq;
namespace QTPBuildObjectLayer
{
public class BuildObject
{
XNamespace NameSpace = "http://www.mercury.com/qtp/ObjectRepository";
public string FilePathObjectName(string FilePath, string LogicName, string ObjectType = "")
{
string ParentNode = "";
string ChildNode = "";
string BuildObjectString = "";
String ObjectList = "";
try
{
if (FilePath == null || LogicName == null)
{
ObjectList = "Please input right FilePath or LogicName";
return ObjectList.ToString();
}
XDocument test = XDocument.Load(FilePath);
var Query = from c in test.Descendants(NameSpace + "Object")
where ((ObjectType == "") ? (c.Attribute("Name").Value == LogicName) : (c.Attribute("Name").Value == LogicName && c.Attribute("Class").Value == ObjectType))
select new
{
IsChildObject = c.Parent.Name.Equals(NameSpace + "ChildObjects"),
LogicNameClass = c.Attribute("Class").Value
//ChildObjectsElementName = c.Attribute("Name").Parent.Parent.Name,
//ParentAttributionName = c.Attribute("Name").Parent.Parent.Parent.Attribute("Name").Value,
//ParentAttributionValue = c.Attribute("Name").Parent.Parent.Parent.Attribute("Class").Value
};
foreach (var Item in Query)
{
ChildNode = "";
ChildNode = Item.LogicNameClass + "(\"" + LogicName + "\")";
if (Item.IsChildObject)
{
ParentNode = ParentNode + BuildParentNode(FilePath, LogicName, Item.LogicNameClass);
}
BuildObjectString = ParentNode + ChildNode;
ObjectList = ObjectList + "@" + (BuildObjectString);
}
return ObjectList;
}
catch (Exception exception)
{
ObjectList = exception.ToString();
return ObjectList;
}
}
public string BuildParentNode(String FilePath, string LogicName, String LogicNameClass)
{
string ParentNode = "";
XDocument ParentObject = XDocument.Load(FilePath);
try
{
var Query1 = from b in ParentObject.Descendants(NameSpace + "Object")
where (b.Attribute("Name").Value == LogicName) && (b.Attribute("Class").Value == LogicNameClass)
select new
{
ParentIsChildObject = b.Parent.Parent.Name.Equals(NameSpace + "ChildObjects"),
ParentAttributionName = b.Parent.Parent.Attribute("Name").Value,
ParentAttributionClass = b.Parent.Parent.Attribute("Class").Value
};
foreach (var Item1 in Query1)
{
ParentNode = Item1.ParentAttributionClass.ToString() + "(\"" + Item1.ParentAttributionName + "\").";
if (Item1.ParentIsChildObject)
{
LogicName = Item1.ParentAttributionName;
LogicNameClass = Item1.ParentAttributionClass;
ParentNode = ParentNode + BuildParentNode(FilePath, LogicName, LogicNameClass);
}
// break;
}
return ParentNode;
}
catch (Exception)
{
return "BuildChildObject Failed";
}
}
}
}
下面也是比较关键的,写了一大堆 东西就是为了实现 一个功能,把转换后的对象字符串、测试数据与对应的事件关联起来,即将读取到的window("aa").edit("b") 及111111 set拼接在一起执行,然后找到对应的方法并执行,这里每一个set.click.doubleclick都是作为 action部分的,每个事件一个方法,如果执行失败就截图并记录即可。
'FunctionName: ExecuteActionSteps
'Description: Execute all actions from this function
'FunctionType:Framework core partion, referenced by Utility Function library,ActionEntry function
Function ExecuteActionStpes(strKeyWords,strObjectName,strParameter,strRepositoriesName)
If strKeyWords="" Then
Reporter.ReportEvent micFail,"Function ActionEntry","Business_Function is null"
Exit function
End If
Environment("DefinedActionName")=strKeyWords
If strRepositoriesName <> "" Then
LoadRepositories RepositoriesName
End If
If strObjectName <>"" Then
If ucase(left(strObjectName,4))="DSC_" Then
strObject=DespritionObject(strObjectName)
else
strObject=BuildObject(strObjectName)
End if
If strObject="" OR strObject="Not Found" Then
Reporter.ReportEvent micFail,"ObjectString:"+strObjectName,"Build object failed,please check your entry or object is described correctly"
Exit function
End If
If strParameter = "" Then
Eval(Trim(strKeyWords)+"("+strObject+")")
else
TestParameter=ReOrganizeParameter(strParameter)
Eval(Trim(strKeyWords)+"("+strObject+","+TestParameter+")")
End If
Else
If strObjectName="" and strParameter="" Then
Eval(Trim(strKeyWords))
else If strObjectName="" Then
TestParameter=ReOrganizeParameter(strParameter)
Eval(Trim(strKeyWords)+"("+TestParameter+")")
End If
End If
End If
End Function
根据eval的结果,自动跳转到action方法部分。以下仅为一个,示例,所以有的均可参照这种方法。其它的类似就不一一重复
'FunctionName:Enter_Value_In_Field
'Descriptions:Enter vlaue in edit box or text box etc.
'Input Parameter:Object String,input parameter and if value is encryped flag
'FunctionType: Framework core functions, referenced by execute action steps
Function Enter_Value_In_Field(strObject,strParameter,IsEncryped)
Enter_Value_In_Field="FAIL"
If strObject.exist(10) Then
strObject.set ""
If Ucase(IsEncryped)="YES" Then
EncypParameter=Crypt.Encrypt(strParameter)
strObject.SetSecure EncypParameter
else
strObject.set strParameter
End If
Enter_Value_In_Field="PASS"
call LogAndCaptureImage(strObject,"Enter_Value_In_Field","PASS","Object:"+strObject.Tostring+" executed successfully")
else
Enter_Value_In_Field="FAIL"
call LogAndCaptureImage(strObject,"Enter_Value_In_Field","FAIL","Object:"+strObject.Tostring+" Not Found")
End If
End Function
最后就是执行的结果需要进行截图,并记录运行每一步的结果
'FunctionName:LogAndCaptureImage
'Descriptions:If Function parameter contain object name, log action execute status and capture img ,if object is null,log execute status
'Input Parameter:strObjectName,ReportName,ReportStatus,ReportDetails
'Output Parameter:None
'FunctionType:Global function, referenced by all actions
Function LogAndCaptureImage(ObjectName,ActionStep,ReportStatus,ReportDetails)
ImageFilePath=Environment("FrameworkPath")+"Test_Result\"+Environment("DefinedTestName")+"\"+cstr(Environment("DefinedTestIteration"))+"_Image"
FormattedCurrentDateTime=year(Date)&month(date)&day(date)&hour(now)&minute(now)&second(now)
ReportStep=ActionStep
ImageFileFullPath=""
If Not IsEmpty(ObjectName) and IsObject(ObjectName) Then
ReserveObject=split(trim(Replace(ObjectName.Tostring,"["," "))," ")
ReserveObjectName=ReserveObject(Lbound(split(ObjectName.Tostring," ")))
ObjectString=BuildObject(ReserveObjectName)
If Ubound(split(ObjectString,")."))>0 Then
TempArray=split(ObjectString,").")
TempObject="set ObjectToCapture="+TempArray(0)+")"
ELSE
TempObject="set ObjectToCapture="+ObjectString
End If
Execute TempObject
If DirectoryOperation.exists(ImageFilePath) = "False" Then
DirectoryOperation.CreateDirectory(ImageFilePath)
End If
ImageFileFullPath=ImageFilePath+"\"+FormattedCurrentDateTime+".png"
If ObjectToCapture.exist(5) and Environment("ImageCaptureLevel") <> "FailedOnly" Then
ObjectToCapture.CaptureBitmap ImageFileFullPath,true
ObjectToCapture.CaptureBitmap ImageFileFullPath,true
If ReportStatus="PASS" Then
If Environment("ImageCaptureLevel") <> "FailedOnly" Then
Reporter.ReportEvent micPass,ReportStep,ObjectName.Tostring+"Finished", ImageFileFullPath
else
'Reporter.ReportEvent micPass,ReportStep,ReportDetails+": "+"<img src='"+ImageFilePath+"\"+FormattedCurrentDateTime+".png"+"' />"
Reporter.ReportEvent micPass,ReportStep,ReportDetails
End if
call GenerateReport(ReportStep,"PASSED",ReportDeatils,ImageFileFullPath)
else
Reporter.ReportEvent micFail,ReportStep,ReportDetails,ImageFileFullPath
call GenerateReport(ReportStep,"FAILED",ReportDeatils,ImageFileFullPath)
End If
Else
If ReportStatus="PASS" Then
Reporter.ReportEvent micPass,ReportStep,ReportDetails
call GenerateReport(ReportStep,"PASSED",ReportDeatils,"")
else
Reporter.ReportEvent micFail,ReportStep,ReportDetails
call GenerateReport(ReportStep,"FAILED",ReportDeatils,"")
End If
End if
End If
End Function
最后一步是压缩成ZIP文件将结果发送至指定邮箱。这个功能多上有很多,这里就不详细介绍了。
'FunctionName:ZipFile
'Description:Zip a file to *.ZIP
'InputParameter:Source file path,desination file path
'FunctionType:Framework core function
Function ZipFile(SourceFolder,ZipFilePath)
Set Fso=createobject("Scripting.FileSystemObject")
for each files in Fso.GetFolder(SourceFolder).Files
If lcase(right(files,4))=".zip" Then
Fso.DeleteFile files.path,True
End If
Next
set File=Fso.CreateTextFile(ZipFilePath,true)
File.Write "PK"& Chr(5) & Chr(6) & String(18, Chr(0))
File.Close
Set objShell=CreateObject("Shell.Application")
Set objSource=objShell.NameSpace(SourceFolder)
Set objFolderItem=objSource.Items()
Set objTarget=objShell.NameSpace(ZipFilePath)
intOptions=256
objTarget.CopyHere objFolderItem,IntOptions
Do
wait 0.5
Loop Until objTarget.Items.Count >0
Set File=Nothing
Set objShell=Nothing
Set WScript=Nothing
End Function
'FunctionName:SendMail
'Description:SendMail to specify user and specify server
'InputParameter:useraccount,userpassword,serveraddress,sendto,mailsubject,mailbody,attachment
'FunctionType:Framework Core function
Function SendMail(UserAccount,UserPassword,SendTo,MailSubject,MailBody,Attachment)
NameSpace="http://schemas.microsoft.com/cdo/configuration/"
Set Email=CreateObject("CDO.Message")
Email.From=UserAccount
Email.To=SendTo
Email.Subject=MailSubject
Email.TextBody=MailBody
If Attachment<>"" Then
If FileExists(Attachment) Then
Email.AddAttachment Attachment
End If
End If
AccountInfo=split(UserAccount,"@",2,1)
With Email.Configuration.Fields
.item(NameSpace&"sendusing")=2
.item(NameSpace&"smtpserver")="smtp."+AccountInfo(1)
.item(NameSpace&"smtpserverport")=25
.item(NameSpace&"smtpauthenticate")=1
.item(NameSpace&"sendusername")=AccountInfo(0)
.item(NameSpace&"sendpassword")=userpassword
.Update
End With
Email.Send
Set Email=nothing
End Function
再补充几个功能,进入节点,和退出QTP自带report结点
'FunctionName:EnterNode
'Description:insert a node,then all event will be logged under this node
'InputParameter:NodeName---TestInteration or ActionInteration;NodeContent,Node description
'OutPutParameter:Node
'FunctionType:Reporting module,Referenced by LogAndCaptureImage
'@Description Create a Node ,then all reporter event will under this node,this function must work together with ExitNode
Public Function EnterNode(ByRef NodeName, ByRef NodeContent)
Set DiscriptionNodeData=CreateObject("Scripting.Dictionary")
DiscriptionNodeData("Status")=MicDone
DiscriptionNodeData("PlainTextNodeName")=NodeName
DiscriptionNodeData("StepHtmlInfo")=NodeContent
DiscriptionNodeData("DllIconIndex")=210
DiscriptionNodeData("DllIconSelIndex")=210
DiscriptionNodeData("DllPath")=Environment("ProductDir")+"/bin/ContextManager.dll"
intContext=Reporter.LogEvent("User",DiscriptionNodeData,Reporter.GetContext)
Reporter.SetContext intContext
End Function
'FunctionName:ExitNode
'Description:Exit current node
'InputParameter:None
'OutputParameter:Node
'FunctionType:Reporting Module,referenced by LogAndCaptureImage
'@Description Exit current node
Public Function ExitNode()
Reporter.UnSetContext
Set DiscriptionNodeData=Nothing
End Function