QTP自动化测试框架:第五章 主要方法介绍(框架核心)
1.测试入口,传递keywords文件及数据文件,所有的用例将以这里为入口
Function StartRun() If Environment("RunWay")=UTFRunMethod Then Environment("DefinedActionIteration")=Environment("DefinedActionIteration")+1 Call ActionEntry (TestFileName,TestSheetName,TestDataFileName,TestDataRangeName) 'Environment("DefinedTestIteration")=Environment("DefinedTestIteration")+1 call WriteIniFile("InitialParameter","Environment('DefinedActionIteration')",Environment("DefinedActionIteration"),InitialFilePath) End If Call ActionEntry (TestFileName,TestSheetName,TestDataFileName,TestDataRangeName) End Function
解释:首先根据读取的配置config.xml文件中运行方式,如果是UTFRunMethod,则默认的循环次数为默认值加1,这里为什么要加1,是因为在读取运行初始参数时循环次数是0,现在开始进入测试,进入第一轮循环,所以要加1。
在call writeinifile()部分即可看到这时候需要更新initialize.ini文件,以记录当前运行至第几轮循环,便于运行出现异常时,可以重新从上次运行失败脚本的下一个轮循环开始。
2.下面正式进入utilityframework部分,首先会对传递过来的参数进行基本的校验,脚本文件及参数是否都存在。然后读取测试数据文件,测试数据文件决定了当前脚本循环的次数,所以注意一点, 这里的循环次数是由测试数据部分控制,而非QTP本身运行设置中的循环次数。
'FunctionName: ActionEntry 'Descriptions:All Action file entry and data file entry, action file name or data file name 'format like testdata.xls or /Module/submodule/testdata.xls,this function will convert it to 'XXX/AutomationFramework/Test_Data/XX.XLS () 'FunctionType: Framework Utility Common Functions Function ActionEntry(TestFileName,TestSheetName,TestDataFileName,TestDataRangeName) strTestFileName=FileNameCheck(TestFileName) strTestTableName=FileNameCheck(TestSheetName) strTestDataFileName=FileNameCheck(TestDataFileName) strTestDataTableName=FileNamecheck(TestDataRangeName) 'TestId=Environment("DefinedTestName") If strTestFileName="Fail" or strTestTableName="Fail" or strTestDataFileName="Fail" or strTestDataTableName="Fail" Then Reporter.ReportEvent micFail,"Function ActionEntry","Please check you input value,Filename check result:"&chr(10)&"strActionFileName="&strTestFileName&";"&chr(10)&"strActionSheetName="&strTestTableName&";"&chr(10)&"strTestDataFileName="&strTestDataFileName&";"&chr(10)&"TestDataRangeName="&strTestDataTableName&";" Exit Function Else strFullTestFilePath=FrameworkPath+"Test_Script\"+TestFileName strFullTestDataFileName=FrameworkPath+"Test_Data\"+TestDataFileName End if TestDataQueryString="Select * from "&TestDataRangeName&" where Ucase(Execute)='YES'" set TestInterationsQuery=ExecuteQuery(strFullTestDataFileName,TestDataQueryString) TestInterationsCount=TestInterationsQuery.RecordCount Set TestInterationsQuery=nothing if Environment("DefinedTestIteration") =< TestInterationsCount then For Interation = Environment("DefinedTestIteration") To TestInterationsCount Environment("DefinedTestIteration")=Interation Call EnterNode((Environment("DefinedTestName")+"_TestInteration_"+cstr(Environment("DefinedTestIteration"))),"TestInteration begin time :"+cstr(now)) Call AddTestDataToDictionary(strFullTestDataFileName,strTestDataTableName,Interation) Call BeginBusinessProcess(strFullTestFilePath,strTestTableName) Reporter.ReportEvent micDone,Environment("DefinedTestName")+"_TestInteration_"&Interation,"TestInteration end time : "+cstr(now) Call ExitNode Next End if 'Call EndTest End Function 'FunctionName:AddTestDataToDictionary 'Description:query test data file and add test data to dictionary 'FunctionType: Function Utilityes,referenced by BeginBusinessProcess Function AddTestDataToDictionary(TestDataPath,TestDataQueryString,TestDataBookMark) TestDataDictionary.RemoveAll Set TestDataRecordSet=ExecuteQuery(TestDataPath,TestDataQueryString) AddTestDataToDictionary=TestDataRecordSet.RecordCount If TestDataRecordSet.RecordCount>1 Then TestDataFieldsCount=TestDataRecordSet.Fields.Count TestDataRecordSet.MoveFirst TestDataRecordSet.Move TestDataBookMark-1 For Index =1 To TestDataFieldsCount If Ucase(TestDataRecordSet.Fields(TestDataFieldsCount-1).Name)="EXECUTE" and Ucase(TestDataRecordSet.Fields(TestDataFieldsCount-1).Value)="NO" Then TestDataRecordSet.Move 1 End If TestDataDictionary.Add TestDataRecordSet.Fields(Index-1).Name,TestDataRecordSet.Fields(Index-1).Value Next End If Set TestDataRecordSet=Nothing End Function
'FunctionName:FileNameCheck 'Descriptions:File name check to check if the input file name is empty and convert to full path 'FunctionType: Framework Utility functions,referenced by ActionEntry function Function FileNameCheck(InputFileName) FileNameCheck="Fail" MyArry=split(InputFileName,"\") If InputFileName="" Then Exit function elseif Ubound(MyArry)>0 then FileNameCheck=MyArry(Ubound(MyArry)) else FileNameCheck=InputFileName End if End Function
解释:首先判断传递过来的脚本文件及数据文件是否都存在,如果这里验证不过,则记录失败日志,直接停止运行
第二步是读取测试数据文件,根据数据文件中的标记,读取本次要用到的测试数据
第三步是控制测试循环次数for 循环,同时更新循环次数
第四步是非常重要的需要创建节点,这里的报告分为两种形势, 一种是QTP自带的,一种是纯EXCEL,的这部分需要对QTP自带的报告进行改写,因为之前QTP每个脚本从action进入后会自动创建节点, 现在我们相当于所以有的节点都从ACTION进入运行,所以想要生成按不同的循环次数及步骤生成报告就需要在每一个循环开始的时候进入节点,循环结束后exit node。这样每一个步骤才能在循环中,记录的报告才清晰。否则会很混乱。。。切记切记
最后一个方法是被上面调用 的,即把测试数据加入数据字典,然后执行的时候即可根据变量名称及循环次数定位要输入 的测试数据,这里测试数据可以 随便加减速,完全不会因为循环次数变化或者脚本调整即可自动添加。唯一 需要注意的是测试数据在EXCEL中的表格是需要命名range或者工作表名称与测试脚本对应的。
3.下面的我就略过,大家可以看英文注释为即明白,因为不是此次框架的重点部分。主要功能是根据测试脚本 中的关键字及对象名称来拼接成测试脚本。
如在原来的QTP中 window("ww").textbox("ww").set 这个地方需要把这一部分拆成不同方法组成 的内容字符串,再通过eval方法来执行字符串。而这里也是重点中的重点。其中涉及到脚本 文件的转换,对象库的转换。
'FunctionName:BeginBusinessProcess 'Descriptions:This function handle the base check for the business process table 'FunctionType: Framework Utility functions,referenced by ActionEntry function Function BeginBusinessProcess(BusinessProcessFileFilePath,BusinessProcessTableName) Datatable.ImportSheet BusinessProcessFileFilePath,BusinessProcessTableName,ActionName BusinessProcessRowsCount=Datatable.GetSheet(ActionName).GetRowCount() If BusinessProcessRowsCount=0 Then Exit function End If For BusinessProcessBaseIndicator = 1 To BusinessProcessRowsCount Datatable.GetSheet(ActionName).SetCurrentRow(BusinessProcessBaseIndicator) strAutoID=Trim(Datatable.RawValue("AUTO_ID",ActionName)) strKeyWords=Trim(Datatable.RawValue("FUNCTION_NAME",ActionName)) strObjectName=Trim(Datatable.RawValue("TEST_OBJECT_NAME",ActionName)) strParameter=Trim(Datatable.RawValue("PARAMETER","Entry")) strRepositoriesName=Trim(Datatable.RawValue("REPOSITORIES_NAME",ActionName)) strExecute=Ucase(Trim(Datatable.RawValue("EXECUTE",ActionName))) If StrExecute="NO" or strExecute="" Then 'Exit for BusinessProcessBaseIndicator=BusinessProcessBaseIndicator+1 else If strAutoID <> "" Then Environment("DefinedTestName")=strAutoID End If If strKeyWords="" Then Reporter.ReportEvent micFail,"Function ActionEntry","Business_Function is null" Exit function ' ElseIf strKeyWords="End_Test" or strKeyWords="End_Function" Then ' Reporter.ReportEvent micDone,"Function ActionEntry",strKeyWords&"executed successfully" ' Exit function End If End if If left(strKeyWords,3)="fn_" Then Call ExecuteBusinessActions(strKeyWords) else Call ExecuteActionStpes(strKeyWords,strObjectName,strParameter,strRepositoriesName) End if ' Datatable.GetSheet(ActionName).SetNextRow Next Datatable.GetSheet(ActionName).SetCurrentRow(1) End Function
4.执行脚本,这里分两种情况,一种是fn_前缀,代表要运行的是function。即由一系列步骤组成 的方法,比如我们在测试某一个功能点的时候,是需要登录,而登录需要输入 用户密码,再点登录,这个时候可以 把登录单独作为 一个测试方法,并命名。在其它地方放在步骤前面,当执行到指定行时会进行判断,根据fn_方法名去查对应的business_configuration文件。
参见下图
'FunctionName: ExecuteBusinessActions 'Description: Execute actions from businessprocess file 'FunctionType:Framework core partion, referenced by Utility Function library,ActionEntry function Function ExecuteBusinessActions(strKeyWords) QueryObjectFilePath=BusinessConfigurationFilePath QueryBusinessProcessString="Select * from [BusinessFunctionReference$] where FUNCTION_NAME="&strKeyWords ActionFileRecord=ExecuteQuery(QueryObjectFilePath,QueryBusinessProcessString) ActionsFilePath=ActionFileRecord("FUNCTION_PATH") ActionsSheetName=ActionFileRecord("fUNCTION_SHEET_NAME") ActionTestDataFileName=ActionFileRecord("TEST_DATA_FILE_NAME") 'Reserved decided by action run mode, current set to business run mode(Action interation not compatabile with test interation) ActionTestDataTableName=ActionFileRecord("TEST_DATA_TABLE_NAME") 'Reserved filed, current script action data name same as action name strFullActionTestDataPath=FrameworkPath+"Test_Data"+ActionTestDataFileName Set ActionFileRecord=Nothing QueryFullActionsFilePath=FrameworkPath+"Test_Script\"+ActionsFilePath QueryActionsFileString="Select * from ["&ActionsSheetName&"$]" Set ActonsFileRecordSet=ExecuteQuery(QueryFullActionsFilePath,QueryActionsFileString) ActionsFileRecordSet.MoveFirst ActionsFileRecordSet.Filter="FUNCTION_NAME='"&strKeyWords&"'" BusinessProcessBaseIndicator=ActionsFileRecordSet.Bookmark ActionsFileRecordSet.Filter="" BusinessFileRowsCount=ActionFileRecordSet.count Set ActonsFileRecordSet=Nothing Datatable.ImportSheet QueryFullActionsFilePath,ActionsSheetName,strKeyWords Datatable.GetSheet(strKeyWords).SetCurrentRow(BusinessProcessBaseIndicator) ActionDataQueryString="Select * from "&Environment("DefinedActionName")&" where Ucase(Execute)='YES'" ActionInterationsCount=AddTestDataToDictionary(strFullActionTestDataPath,ActionDataQueryString,1) If ActionInterationsCount>0 and Environment("DefinedActionIteration") < ActionInterationsCount Then For ActionInteration = Environment("DefinedActionIteration") To ActionInterationsCount Environment("DefinedActionIteration")=ActionInteration Call EnterNode("ActionInteration_"+Cstr(Environment("DefinedActionIteration")),"ActionInteration_"+Cstr(Environment("DefinedActionIteration"))+" begin time : "+cstr(now)) Call AddTestDataToDictionary(strFullTestDataFileName,ActionDataQueryString,ActionInteration) Call BeginBusinessProcess(strFullTestFilePath,strTestTableName) Reporter.ReportEvent micDone,"ActionInteration : "&ActionInteration,"ActionInteration end time : "+cstr(now) Call EnterNode For StartRow=BusinessProcessBaseIndicator To BusinessFileRowsCount strKeyWords=Trim(Datatable.RawValue("FUNCTION_NAME",strKeyWords)) strObject=Trim(Datatable.RawValue("OBJECT_NAME",strKeyWords)) strParameter=Trim(Datatable.RawValue("PARAMETER",strKeyWords)) strRepositoriesName=Trim(Datatable.RawValue("REPOSITORIES_NAME",strKeyWords)) strExecute=Ucase(Trim(Datatable.RawValue("EXECUTE",strKeyWords))) If strExecute="YES" and strKeyWords<>"END_FUNCTION" and strKeyWords<>"END_TEST" Then call ExecuteActionStpes(strKeyWords,strObject,strParameter,strRepositoriesName) else Reporter.ReportEvent micDone,ExecuteBusinessActions,"This step skipped as the keywords is END_FUNCTION or END_TEST" Exit for End If Next Next Else For StartRow=BusinessProcessBaseIndicator To BusinessFileRowsCount strKeyWords=Trim(Datatable.RawValue("FUNCTION_NAME",strKeyWords)) strObject=Trim(Datatable.RawValue("OBJECT_NAME",strKeyWords)) strParameter=Trim(Datatable.RawValue("PARAMETER",strKeyWords)) strRepositoriesName=Trim(Datatable.RawValue("REPOSITORIES_NAME",strKeyWords)) strExecute=Ucase(Trim(Datatable.RawValue("EXECUTE",strKeyWords))) If strExecute="YES" and strKeyWords<>"END_FUNCTION" and strKeyWords<>"END_TEST" Then call ExecuteActionStpes(strKeyWords,strObject,strParameter,strRepositoriesName) else Reporter.ReportEvent micDone,ExecuteBusinessActions,"This step skipped as the keywords is END_FUNCTION or END_TEST" Exit for End If Next End If End Function '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
5.以下部分是执行查询部分,通过ado方式操作EXCEL文件,注意这里读取EXCEL数据共用了两种方式。作为公共的方法,可在多个地方被调用。
a.直接导入QTP的table
b.ado读取
写入方法也分两种
a.借助以下方法直接insert。
b.需要打开EXCEL进行写,完全依赖于excel对象。
'FunctionName:ExecuteQuery 'Description: execute sql query from this action. 'FunctionType:Commmon functions referenced by multiple functions. Function ExecuteQuery(QueryObjectFilePath,QueryString) Const AdUseClient=3 Set ObjectConnection=CreateObject("ADODB.Connection") Set ObjectRecordSet=CreateObject("ADODB.RecordSet") ObjectConnection.ConnectionString="Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"&"DBQ="&QueryObjectFilePath&";ReadOnly=False" ObjectConnection.Open ObjectRecordSet.CursorLocation = adUseClient ObjectRecordSet.Open QueryString,ObjectConnection,3,3 Set ExecuteQuery=ObjectRecordSet Set ObjectConnection=Nothing Set ObjectRecordSet=Nothing End Function
6.生成测试报告 文件,EXCEL格式
'FunctionName:GenerateReport 'Description: insert action execute status to an excel file to generate a lite report 'FunctionName: Referenced by all action functions, core function Function GenerateReport(ActionName,Status,ReportDetails,ImageFilePath) ReportFilePath=Environment("DefinedReportFilePath") ReportSheetName=cstr(Environment("DefinedTestName"))+"_"+cstr(Environment("DefinedTestIteration")) SelectString="select * from "+" ["+ReportSheetName+"$]" Set ReportedRow=ExecuteQuery(ReportFilePath,SelectString) ReportedRowNum=ReportedRow.Recordcount Set ReportedRow=Nothing InsertString="Insert into "+"["+ReportSheetName+"$](TestName,ActionName,ExecuteStatus,ExecuteDetails,ImageFilePath,ExecuteTime) Values('"+Environment("DefinedTestName")+"','"+Environment("DefinedActionName")+"','"+Status+"','"+ReportDetails+"','"+ImageFilePath+"','"+cstr(now)+"')" 'InsertString="Insert into "+"["+cstr(Environment("DefinedActionIteration"))+"$]"+"(TestName,ActionName) "+ "Values("+Environment("DefinedTestName")+","+Environment("DefinedActionName")+")" Const AdUseClient=3 Set ObjectConnection=CreateObject("ADODB.Connection") Set ObjectRecordSet=CreateObject("ADODB.RecordSet") ObjectConnection.ConnectionString="Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"&"DBQ="&ReportFilePath&";ReadOnly=False" ObjectConnection.Open ObjectRecordSet.CursorLocation = adUseClient ObjectRecordSet.Open SelectString,ObjectConnection,3,3 If Not ObjectRecordSet.EOF Then ObjectRecordSet.MoveLast End If ' ObjectRecordSet.execute InsertString ObjectRecordSet.Close ObjectRecordSet.Open InsertString,ObjectConnection,3,3 ' ObjectRecordSet.Update Set ObjectConnection=Nothing Set ObjectRecordSet=Nothing End Function 'FunctionName:ReOrganizeParameter 'Description: organizeparameter "mercury"|Test|ENV_TEST as "Mercury",Test,Env_vironment and connect with function name to run corresponding functions 'FunctionType:Commmon functions referenced by ExecuteActionStpes,core functions 'FunctionName:GenerateReportFile 'Description:Framewrok core functions ,mainly to generate a excel report file 'ParameterInput:None 'FunctionType:Framewrok Utility Functions and referenced by start_test ' Sub GenerateReportFile() CurrentDate=year(Date)&month(date)&day(date) CurrentTime=year(Date)&month(date)&day(date)&hour(now)&minute(now)&second(now) ReportName=cstr(Environment("DefinedTestName"))+"_Report.xlsx" TestReportPath=Environment("FrameworkPath")+"Test_Report" ReportPath=Environment("FrameworkPath")+"Test_Report\"+CurrentDate+"\"+Environment("DefinedTestName") ReportFilePath=ReportPath+"\"+ReportName Environment("DefinedReportFilePath")=ReportFilePath set ExcelObject=CreateObject("Excel.Application") If Environment("RunMode")="DebugRunMode" and DirectoryOperation.Exists(ReportPath)="True" Then DirectoryOperation.Delete ReportPath,True 'debug run mode delete all files in subfolder DirectoryOperation.CreateDirectory(ReportPath) End If If FileOperation.Exists(ReportFilePath)="False" Then If DirectoryOperation.Exists(ReportPath)="False" Then DirectoryOperation.CreateDirectory(ReportPath) End If ExcelObject.Workbooks.Add ExcelObject.ActiveSheet.Name=cstr(Environment("DefinedTestName"))+"_"+cstr(Environment("DefinedTestIteration")) With ExcelObject.Sheets(cstr(Environment("DefinedTestName"))+"_"+cstr(Environment("DefinedTestIteration"))) .Range("A1")="TestName" .Range("B1")="ActionName" .Range("C1")="ExecuteStatus" .Range("D1")="ExecuteDetails" .Range("E1")="ImageFilePath" .Range("F1")="ExecuteTime" End With ExcelObject.ActiveWorkbook.SaveAs ReportFilePath End If ExcelObject.Workbooks.Open(ReportFilePath) For i = 1 To ExcelObject.Worksheets.Count If ExcelObject.Worksheets(i).name=cstr(Environment("DefinedTestName"))+"_"+cstr(Environment("DefinedTestIteration")) Then SheetFound=True Exit for Else SheetFound=False End If Next If SheetFound=False Then ExcelObject.Sheets.Add.Name = cstr(Environment("DefinedTestName"))+"_"+cstr(Environment("DefinedTestIteration")) With ExcelObject.Sheets(cstr(Environment("DefinedTestName"))+"_"+cstr(Environment("DefinedTestIteration"))) .Range("A1")="TestName" .Range("B1")="ActionName" .Range("C1")="ExecuteStatus" .Range("D1")="ExecuteDetails" .Range("E1")="ImageFilePath" .Range("F1")="ExecuteTime" End With ExcelObject.ActiveWorkbook.Save End If ExcelObject.Workbooks.Close ExcelObject.Application.Quit ExcelObject.Quit Set ExcelObject=Nothing End Sub
7.读写INI文件,至于 为什么 把这一部分放核心功能,而不是一开始action部分,一个原因是可能会在其它地方调用 ,另外 一个是因为QTP中不同文件中传递参数时除了方法外,环境变量外,其它的并不能直接以变量形式调用 ,所以需要放在框架核心部分。具体引用dll部分,需要参照第四章内容,至此,基本的就到这里,对于工作量最大的一部分,主要 是如何做到支持任何平台,包括 BS.CS或其它语言的。将会在下一章节介绍。
Function ReadIniFile(SectionName,KeyName,InitialFilePath) ReadIniFile=Extern.GetPrivateProfileInt(SectionName,KeyName,1000,InitialFilePath) '10000 just use to distinguish an exception when required key or section not found. If CLng(ReadIniFile)=1000 Then Reporter.ReportEvent micFail,"ReadIniFile","KeyName : "+KeyName + "in Section "+SectionName+"in fILE: "+InitialFilePath+"Not Found" Msgbox "Section or KeyName not found" ExitAction() End If End Function Function WriteIniFile(SectionName,KeyName,KeyVlaue,InitialPath) Extern.WritePrivateProfileString SectionName,KeyName,KeyVlaue,InitialPath End Function
上一篇: Python如何连接MySQL
下一篇: win10重装系统后少了一个盘如何解决?